Home Implementing Polyglot Persistence – Part 5
Post
Cancel

Implementing Polyglot Persistence – Part 5

In this post I will complete the implementation of my MongoDB repository by implementing the Review operations previously defined in my IProductRepository interface. This will also be the post where I visit some of the Create, Update, and Delete API’s of the MongoDB C# Drivers. Everything up to this point has been variations of Read API’s.

1
2
3
4
5
6
// Review Operations
Review GetReview(string reviewId);
List<Review> GetReviews(string prodId, int pageIndex, int pageSize);
string AddReview(string prodId, Review review);
bool UpdateReview(string reviewId, Review review);
void DeleteReview(string reviewId);

However, before I get into the implementation of these methods, I need to revisit my MongoHelper class to support a new collection in MongoDB called “Reviews”, which is the name of the collection where I’ll be storing product reviews.

Update MongoHelper to Support my “Reviews” Collection in MongoDB

In part 3 I first introduced my MongoHelper class and talked about class maps. For the reviews collection, I’ll need a similar class map, but this time only to indicate that the “Id” field in my Review class will be represented as an ObjectId. To achieve this, I added this small piece of code to my RegisterClassMaps method.

1
2
3
4
5
BsonClassMap.RegisterClassMap<Review>(cm =>
{
    cm.AutoMap();
    cm.IdMemberMap.SetRepresentation(BsonType.ObjectId);
});

While I was in this file, I also added a new read-only property to return a reference to the Reviews collection. The reviewsCollectionName is a string set from an AppSetting in web.config (just like I did for the products collections).

1
2
3
public static MongoCollection<Review> ReviewsCollection {
    get { return mongoDatabase.GetCollection<Review>(reviewsCollectionName); }
}

With those few changes in place, I can now proceed to the implementation of the Review operations.

The GetReview Implementation

This method is among the simplest in all the methods I’ll cover in this post and the use case is very straight forward – you just want to retrieve a single review for a product. The way I’ve setup my controller, a review is accessed by including the “Id” of the review in the URL. For example,

HTTP GET Review

Recall that my class map defines the Id property as an ObjectId. So, to retrieve this Id, I just need to look for it in the collection using the FindOneById method.

1
2
3
4
5
6
7
8
public ProductService.Model.Review GetReview(string reviewId)
{
    ObjectId objectId;
    if (ObjectId.TryParse(reviewId, out objectId))
        return MongoHelper.ReviewsCollection.FindOneById(objectId);
    else
        return null;
}

The GetReviews Implementation

This method returns a list of reviews for a given product Id. Since there could be a large number of reviews, this method also supports some basic pagination. But, to simply return all reviews for a product Product Id, this URL would work.

HTTP GET Reviews

In this implementation, I’m building a query that will run on the server, searching the Reviews collection for all reviews with a ProdId matching the product Id passed in on the URL. Then, I simply pass that query into the Find method with the necessary pagination (skip, take).

1
2
3
4
5
6
7
8
9
10
11
12
public List<ProductService.Model.Review> GetReviews(string prodId, int pageIndex, int pageSize)
{
    ObjectId objectId;
    if (ObjectId.TryParse(prodId, out objectId))
    {
        var query = Query<Review>.EQ(r => r.ProdId, objectId.ToString());
        return MongoHelper.ReviewsCollection.Find(query).
            Skip(pageIndex * pageSize).Take(pageSize).ToList<Review>();
    }
    else
        return null;
}

The AddReview Implementation

This is the first method where we actually add something to a collection. The use case here is a user has purchased a product and wants to write a review for it. For this, you need to POST data to the server using this URL and JSON in the Request Body of the message.

HTTP POST Add Review

You may notice in the JSON that I didn’t specify things like ProdId, Id, and ReviewDate. All of which are properties of the Review class. I chose to set these explicitly in the method. For ProdId, I use the product Id from the URL. For ReviewDate, I just timestamp the document with the current time. And, for Id, I’m generating an new ObjectId before inserting.

1
2
3
4
5
6
7
8
public string AddReview(string prodId, ProductService.Model.Review review)
{
    review.Id = ObjectId.GenerateNewId().ToString();
    review.ProdId = prodId;
    review.ReviewDate = DateTime.UtcNow;
    MongoHelper.ReviewsCollection.Insert(review);
    return review.Id;
}

The UpdateReview Implementation

To update an existing review, this translates to a PUT verb on my controller with similar JSON in the Request Body for the data I want to update.

HTTP PUT Update Review

In the implementation, I’m applying updates to the properties of the existing review. I’m creating a query to find the review Id passed in. Next, I’m telling MongoDB to update the ReviewDate, Rating, and Comments fields in the review. The Combine method is particularly handy when you need to make updates to multiple fields in the document.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public bool UpdateReview(string reviewId, ProductService.Model.Review review)
{
    ObjectId objectId;
    if (ObjectId.TryParse(reviewId, out objectId))
    {
        var query = Query<Review>.EQ(r => r.Id, objectId.ToString());
        var updates = Update<Review>.Combine(
            Update<Review>.Set(r => r.ReviewDate, DateTime.UtcNow),
            Update<Review>.Set(r => r.Rating, review.Rating),
            Update<Review>.Set(r => r.Comments, review.Comments));
        var result = MongoHelper.ReviewsCollection.Update(query, updates);
        return result.Ok;
    }
    else
        return false;
}

The DeleteReview Implementation

Finally, to remove a review document from the reviews collection, the DELETE verb is set with the URL indicating the id of the review to delete.

HTTP DELETE Delete Review

Once the reviewId is parsed into an ObjectId, it’s a simple matter of finding the document and calling Remove.

1
2
3
4
5
6
7
8
9
public void DeleteReview(string reviewId)
{
    ObjectId objectId;
    if (ObjectId.TryParse(reviewId, out objectId))
    {
        var query = Query<Review>.EQ(r => r.Id, objectId.ToString());
        MongoHelper.ReviewsCollection.Remove(query);
    }
}

Conclusion

This wraps up my journey through the document database category and MongoDB-as-a-servicefrom Mongolab. The service from Mongolab is very powerful and easy to use. The C# Drivers are a gem and the more I use them the more I appreciate everything they do.

My solution is available here for anyone interested in reviewing the full end-to-end implementation.

This post is licensed under CC BY 4.0 by the author.

Implementing Polyglot Persistence – Part 4

Visual Studio and GitHub: The Basics of Working with Existing Repositories

Comments powered by Disqus.

Trending Tags