CSMongo On GitHub

I've been hammering away at the keyboard for a few weeks now and my beta version of CSMongo is now live on GitHub!

I've written a lot of documentation in for the project in the Wiki section on the site, so if you're interested you can start reading the details of how the code works.

In this post I'll just go over some of the more interesting things the CSMongo does to make working with Mongo easier than normal.

Anonymous Types and Dynamic Creation

Working with documents, including those with multiple levels, is a snap with CSMongo. You have many ways to make changes but each of these ways also allow you to create entirely new sections of your document.

MongoDocument document = new MongoDocument();

//add some new items
document += new {
    name = "Hugo",
    age = 30,
    settings = new {
        font = "arial",
        color = "orange"
    }
};

//set values for a lower level field
document.Set("browser.urls", new object [] {
    new { site = "google.com", favorite = false },
    new { site = "hugoware.net", favorite = true, icon = "blue-icon.ico" }
});

//or create new elements with an index path
document["blog.url"] = "http://somewebguy.wordpress.com";

//or use existing objects as a template
Uri address = new Uri("http://www.herdingcode.com");
document += address;

Nifty Anonymous Type Mapping Method

One thing that I didn't like was always having to refer to elements using a string. I had a moment late one night ... er... maybe it was early one moring... like around 1AM or so -- Why can't I use a return anonymous type value to act as a template for the values to use. Here is an example of what I put together...

//grab a document - Assume that the value returned
//looks like the JSON example below
MongoDocument document = database.Find("users").SelectOne();
//{
//    name : "Jimmy",
//    age : 50,
//    website : "http://www.hugoware.net"
//    settings : {
//        font : "arial",
//        color : "red"
//    }
//}

//provide an anonymous type as the template to return
//Notice the values provide match in some places but not 
//in other areas
var value = document.Get(new {
    name = "no name",
    age = -1,
    admin = false,
    favorite = Mongo.Null,
    settings = new {
        color = "black",
        version = 0
    }
});

//now we have an anonymous type with the values
//it could find and then the default values for the
//sections it couldn't find or was missing
value.name; // "Jimmy"
value.age; // 50
value.admin; // false (fallback)
value.favorite; // null (fallback)
value.settings.color; // "red"
value.settings.version; // 0

This means that we can refactor our code without needing to update a bunch of string values. You can even use this mapping option directly after a query so all of the values are converted into the new type automatically.

Lazy Collections

When you're making changes to a MongoDatabase, for the most part all of the commands are immediate - meaning they connect to the database right away and perform their work. However, most commands inside of a MongoCollection don't execute until you call the SubmitChanges method. This can allow you to queue up a few inserts and deletes or make changes to documents that have been loaded into memory and then update them all at once. The code below illustrates how it works.

//Inserting Documents
//=================================
MongoCollection collection = database.GetCollection("users");

//add a few documents
collection.InsertOnSubmit(new { name = "Hugo" });
collection.InsertOnSubmit(new { name = "Mary" });
collection.InsertOnSubmit(new { name = "Gwyn" });
collection.InsertOnSubmit(new { name = "Cassie" });

//nothing has been inserted yet, do it now
collection.SubmitChanges();

//Performing Updates
//=================================
MongoCollection collection = database.GetCollection("users");
var documents = collection.Find()
    .Greater("age", 50)
  .Select();

//make each of the changes
foreach(MongoDocument document in documents) {
    document += { isOld = true };
}

//documents are only changed in memory
//send the update to the server
collection.SubmitChanges();

//Deleting Documents
//=================================
MongoCollection collection = database.GetCollection("users");
var documents = collection.Find()
    .Greater("age", 50)
  .Select();

//mark each for deletion
foreach(MongoDocument document in documents) {
    collection.DeleteOnSubmit(document);
}

//documents are only changed in memory
//send the update to the server
collection.SubmitChanges();

Of course, you can perform a blanket update statement using a query from the MongoDatabase object itself, but this is a good example of how a MongoCollection can do it in a lazy way.

It is also worth mentioning that if you use the GetCollection method to work with a collection then it is also monitored by the database. This means that if you call the MongoDatabase method SubmitChanges then it will check each of the collections it is tracking and submit their changes automatically.

February 28, 2010

CSMongo On GitHub

CSMongo is now available on Github!