Experimenting with MongoDB from C#

Wednesday, October 14, 2009

I’ve often felt that we treat relational databases as a hammer to use with every kind of nail, screw, bolt, rivet, metric nut, and wall anchor we encounter in software development. The modern relational databases is a marvelous piece of engineering, and we have centuries of collective experience in designing, optimizing, securing, and managing them, but they just aren’t the best fit for every scenario.

The last few months I’ve been keeping an eye on the growing No-SQL movement. I’d like to make room for the No-SQL conference (nosqleast – their motto is: select fun, profit from real_world where relational=false;), but I’ll just have to wait for a debrief from Matt P. Here are a couple great blog posts for background on the No-SQL thing:

MongoDB I wanted to experiment with a document oriented database myself and chose MongoDB. From the FAQ:

MongoDB is an document-oriented DBMS. Think of it as a persistent object store. It is neither a relational database, nor even "table oriented" like Amazon SimpleDB or Google BigTable. If you have used object-relational mapping layers before in your programs, you will find the Mongo interface similar to use, but faster, more powerful, and less work to set up.

I chose MongoDB because it looked easy to setup and run with.

  1. Download and extract the binaries from MongoDB downloads.
  2. Create a c:\data\db directory (that’s the default storage location – you can override it)
  3. Run the MongoDB daemon – mongod.exe

To talk to MongoDB I used mongodb-csharp. You can either download the source as a zip file, or use a Git client like Git on Windows to clone the github repository. Sounds difficult, but Git is easy once you’ve adopted to the terminology, and as a bonus, it’s screaming fast. There is a Visual Studio solution included with the sources, so you can open it, build it, and out pops a MongoDB.Driver assembly.

Connecting to a database looks like this:

var mongo = new Mongo();
mongo.Connect();
var db = mongo.getDB("movieReviews");

I’m running MongoDB on the local machine and it’s listening on the default port with no special security settings. That simplifies the code, but also notice I can ask for a database (movieReviews), and if it doesn’t exist MongoDB will create the database for me. I don’t need to create tables or schemas or setup primary keys. It just works. I’m thinking document oriented databases are to relational databases what dynamic languages are to static languages.

The next step is to get/create a collection and start adding documents to it.

var movies = db.GetCollection("movies");

var movie = new Document();
movie["title"] = "Star Wars";
movie["releaseDate"] = DateTime.Now;
movies.Insert(movie);

A collection is somewhat analogous to a table in the RDBMS world, but instead of rows and columns a collection is a bunch of documents that internally are stored in a binary JSON format (BSON). The documents can contain anything – they are schemaless, but MongoDB understands how to index and query the documents.

var spec = new Document();
spec["title"] = "Star Wars";
var starWars = movies.FindOne(spec);

With a few more abstractions (and a little bit of LINQ), document oriented databases could be a huge hit in .NET. Although, they might be better aligned with a language that runs on the DLR…


Comments
gravatar Jack Thursday, October 15, 2009
nice, I like it very much!
gravatar Mike Borozdin Thursday, October 15, 2009
What about relationships between entities? How are they handled?
gravatar dm Thursday, October 15, 2009
@mike it is possible to have a reference from one object/document to another - although generally this will require an additional client/server turnaround to "traverse". so you can do it but the typical way to use mongodb is to design a schema where the number of references between objects is not too high.

one way to do that is to embed objects within others. you can nest objects and arrays of objects which then has all the data one typically needs together in the first place. see "reaching into objects" and "schema design" pages on the mongodb.org site...
gravatar developingchris Thursday, October 15, 2009
At pyohio, one of the engineers from SourceForge, presented on the fact that they are completely running on MongoDB now. He showed benchmarks for mySql, mongo, couch and 6 other ones that I don't have notes on. The short story is that mongo out performed all of them by hundreds of percent of transactions . It even seemed to scale much closer to linear on inserts when approaching 1 million documents in the db.
Sam Corder Thursday, October 15, 2009
Hey thanks for the nice write up. A lot of times when I'm working with the driver I like to use the default item methods so I can shorten the code a bit. Also Document has an Append method that returns itself so that you can chain it. You can squash your movies example down to one line.

db["movies"].Insert(new Document().Append("title", "Star Wars").Append("releaseDate", DateTime.Now);

In practice that might not look so pretty but it makes sending a query a little easier.

var cursor = db["movies"].FindOne(new Document().Append("title", "Star Wars"));

As for Linq support, I recently merged in a contribution. There aren't any binaries up yet but compiling from source should work fine.
gravatar scott Thursday, October 15, 2009
@Sam: Excellent, thanks for the tips!
AspNetSpy Thursday, October 15, 2009
This post has been spied by AspNetSpy.com
gravatar Arne Claassen Thursday, October 15, 2009
If you want to get some examples of how the (albeit basic) Linq support Sam mentioned works, I wrote up a post on the contrib here: www.claassen.net/...
Dave Monday, October 19, 2009
This seems to work well,

However I am having trouble trying to deserialize an object using JSON.NET

Movie m = JsonConvert.DeserializeObject<Movie>(starWars.ToString());

public class Movie
{
public Oid _id { get; set; }
public string title {get;set;}
public DateTime releaseDate { get; set; }

}

What is the Trick?
Dave Monday, October 19, 2009
This seems to work well,

However I am having trouble trying to deserialize an object using JSON.NET

Movie m = JsonConvert.DeserializeObject<Movie>(starWars.ToString());

public class Movie
{
public Oid _id { get; set; }
public string title {get;set;}
public DateTime releaseDate { get; set; }

}

What is the Trick?
gravatar Cedric Monday, December 7, 2009
HOw would these databases handle ,temporal data
gravatar kellyb Tuesday, February 2, 2010
Do you know of any Windows base web hosting providers that offer MongoDB support?
gravatar Daniel Wertheim Friday, February 5, 2010
Nice article.

I have written some examples of how to use Json.Net to get the mappings to work as well as how to use Castle Dynamic proxy to take care of the mappings.

daniel.wertheim.se/...

//Daniel
gravatar Daniel Wertheim Friday, February 12, 2010
Nice to know...
Samus has fixed the issue with the Oid.ToString implementation in the MongoDb-driver, so it shall now give correct json. I don't know if it has reached the master-version yet.

I made a follow up to my initial post, where I just did some refac. to show how it could be used.

daniel.wertheim.se/...

//Daniel
gravatar Toren Monday, May 3, 2010
Since I am coding in Vs 2005 and cannot use C# 3.0 I need to know the types that go in place of var. I have figured out all except the collections one.
gravatar Jim Wooley Monday, May 17, 2010
Toren, The var keyword simply indicates that the compiler can infer the data type. If you don't have any projections (Select where the shape changes), then the type will be the same as the source (Document). Otherwise, you may need to project into a type you create explicitly in 2005:

Foo = new Foo(doc[Field1], doc[Field2]);

This is not specific to MongoDb, but applies generally when looking at C# 3 + code and applying it to C# 2.
Sudip Wednesday, June 9, 2010
It's a nice startup for me
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!