Skip to content

Going 'NoSQL' with MongoDB and C#

I've noticed with interest the 'NoSQL' movement which seems to have arrived recently and have on the whole ignored it. I generally find myself getting on well with relational databases and based on that fact (and the fact they are so commonly used), I have not looked into any of the alternatives. However, I have recently read various articles talking in particularly about CouchDB and MongoDB and after reading a little bit about both, I decided to give MongoDB a closer look.

What Is MongoDB?

MongoDB is a fast and lightweight schema-less document-oriented database. Essentially, rather than having a database with tables consisting of a number of rows, you have a database with a set of collections. Each collection holds a number of documents. Now I know what you're thinking – it sounds like exactly the same thing but using different terminology. I guess it can be thought of like that but the big difference is the 'schema-less' aspect. Not all the documents in a given collection have to be structured the same way. In fact, its quite possible to store completely different documents in the same collection. In practice, I imagine its more likely that you'd probably keep the same or similar items in a collection, but it certainly provides more flexibility should it be needed. It could also be useful in the case where you are storing an object hierarchy and the documents share some common fields but not all.

MongoDB also allows each document to have "sub-documents". For example, its possible for a Person document to have an Address sub-document (with all the appropriate fields like city, postal code etc on it). Sometimes this might make more sense than the traditional relational model where you have your people in the People table and the addresses in the Addresses table.

This has only scratched the surface of what MongoDB can really do. I would recommend taking a look at Wynn Netherland's slides on the subject (ruby-oriented but a great intro to MongoDB) and some of the articles linked from the MongoDB site.

How Do I Use IT?

There are official MongoDB drivers for lots of languages and platforms such as Ruby, PHP and Python, along with several community-maintained ones for other languages. The MongoDB site holds a pretty comprehensive list. It is one of the community-maintained ones which I have used to connect and make use of MongoDB from .NET: MongoDB-CSharp.

Scott Allen has written a great post on using MongoDB-CSharp, and this has been followed up by another great post by Hernan Garcia, where he abstracts the MongoDB stuff behind a nicer model layer which he can then work with from within his app.

My app did not use this technique, rather it is right down-to-the-metal MongoDB Document all the way. Not the sort of thing you'd want in a production app, but my aim was to have something simple and basic working. I also do not like the way Hernan's domain entities have to know so much about how MongoDB works either – something I will try to look at and write a follow-up post on I think.

MongoDbNotes Project

I've babbled on for long enough, lets get to some code. My application is a small ASP.NET MVC 2 app which allows the user to add simple post-it style notes (with a title and a body) to the site, tag them, and delete them. At the moment it's missing any other functionality (like editing), but you get the idea.

Unlike the approach Hernan uses, I am connecting to the database right upfront during the Application_Start and storing it for use throughout the app in my IoC container (Autofac in this case).

public static MongoDB.Driver.Database ConnectMongoDb() {
    var host = ConfigurationManager.AppSettings["mongo-host"];
    var port = int.Parse(ConfigurationManager.AppSettings["mongo-port"]);
    /* username, password and database too */

    var mongo = new Mongo(host, port);
    mongo.Connect();
    var db = mongo.getDB(dbname);

    if (! string.IsNullOrEmpty(username)) {
        db.Authenticate(username, password);
    }

    return db;
}

The MongoDB.Driver.Database instance here is then injected into my repository implementation (NoteRepository) when it is needed, where it can be queried and inserted into. It is in this repository where I have placed all the logic for querying, saving and deleting entities.

Scott Allen's post talks about querying the database by passing it an example of what you would like (he uses movies). I have made use of this to create a FindById method. It takes an Oid instance and then returns the document which has this ID in its _id field. It is worth noting that all documents inserted into MongoDB have an _id field automatically added. You can think of it a bit like an auto-incrementing ID from MySQL or the like, but it is generally not an integer (rather its a collection of bytes generally represented as a hex string). I make use of this for specifying deletion criteria as well.

Another thing worth mentioning is MongoDB's concept of an 'upsert'. This is an insert or an update – whichever is appropriate. If the item you are attempting to add does not yet exist, it is an insert and if it does, it is an update. MongoDB-CSharp provides access to this facility through the Collection.Update method by taking an additional parameter in one of its overloads. Not too sure why it's an integer rather than a boolean but still, it works.

MongoNotesDb screenshots

Get The Code

The MongoDbNotes app lives in my experimental repository on GitHub. You can get the latest version by cloning it or asking GitHub for a download. I'm sure there's a fair amount of improvement which can be done to the app (editing would probably be good) so feel free to have a play. Don't forget to grab yourself the latest stable MongoDB version first too – it runs on Windows, OS X and Linux.

Conclusions

I like MongoDB. I like it enough to make the decision for it to power the next version of this site (which will be Rails-powered too). However I do think that it is still very young, particularly in relation to .NET. I think that within the Ruby community it has gained a fair bit of traction and therefore has more open-source solutions centring around it but in terms of .NET, it still has a long way to go – the fact that at present you have to work bare-metal with Documents and things or effectively roll your own O/R mapping layer proves that. But don't let this stop you giving it a test-drive.