Hugoware

The product of a web developer with a little too much caffeine

CSMongo On GitHub

with 16 comments

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"] = "https://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 TM

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.

Try It Out!

If you’ve haven’t been sure if you want to try out MongoDB yet then now is a great time! The links below can help you get started!

Getting Started
MongoDB Website
Using MongoDB With Visual Studio

Source Code
CSMongo on GitHub
CSMongo Wiki Help on GitHub

Written by hugoware

March 1, 2010 at 12:35 am

16 Responses

Subscribe to comments with RSS.

  1. Awesome. I like how you’ve tied in the Anon. Type here as well.

    ActiveEngine Sensei

    March 1, 2010 at 8:24 am

    • Thanks man! I got into some pretty crazy stuff (at least for me) working with real anonymous types and mapping them to nodes on the MongoDocument. I’ve got some cool blog posts lined up about how it works.

      hugoware

      March 3, 2010 at 3:01 pm

  2. Hi, i downloaded from github and was getting an error on helpers.cs in line 19:
    File.WriteAllText(path, output.ToString());
    i commented it and now seems to be working…

    i’ll keep trying it, i like a lot the logic you use to handle Mongo data.

    Thank you

    Jorge Garcia

    March 3, 2010 at 1:23 pm

    • Ah… well that is embarrassing…

      My helper method was so I could examine output after it was written to the stream… Unless you have a “D:\Output\” folder then it is going to crash…

      Thanks for pointing that out!

      hugoware

      March 3, 2010 at 2:56 pm

    • … and thanks! I tried to make the objects feel as dynamic as possible 🙂

      hugoware

      March 3, 2010 at 2:59 pm

  3. Thanks for the awesome driver..

    however, i have one question about update.

    how to send update to mongo.
    say: user edit his profile, we get the data from mongo, and display it in the page. User modified it and submit the changes.

    question is: do I need to retrieve the data again from mongo, and merge the fresh one with what modified data before submitting it? or just submit the data from the user straight to mongo.

    I tried both, but the data doesn’t get updated. what am i missing from here?

    My first approach: (no luck)
    public void Update(UserProfile profile)
    {
    if (profile._id == null) // doens’t have existing mongo ID
    return;

    var doc = new MongoDocument(profile);
    var coll = database.GetCollection(“Profiles”);
    coll.UpdateOnSubmit(doc);
    coll.UpdateOnSubmit(doc);
    }

    My 2nd approach: (no luck)
    public void Update(UserProfile profile)
    {
    if (profile._id == null) // doens’t have existing mongo ID
    return;

    var coll = database.GetCollection(“Profiles”);
    var existing = coll.Find().FindById(entity._id).SelectOne();
    existing += profile;
    coll.UpdateOnSubmit(existing );
    coll.UpdateOnSubmit(existing );
    }

    Hery

    March 17, 2010 at 3:10 pm

  4. Is there any reason why CSMongo doesn’t support mapping to non-anonymous class?

    To achieve this, I have to create extension class to MongoDocument, so it can be mapped to the domain class via reflection.

    Hery

    March 17, 2010 at 3:13 pm

    • I actually have a method added in there called Populate for that purpose (to dynamically populate an object… granted it doesn’t do anything yet)

      The problem I’ve run into is that I’m not entirely sure how I want to handle this… Here is why…

      According to .NET casing conventions you’re supposed to use Pascal case for Properties (in fact, that is pretty much how I see everyone writing their code).

      But then take your typical Mongo object — They use ‘camel case’ or whatever you want to call it (first letter is lowercase)

      So here is my quandary… Do I recase the names when casting back and forth from Mongo do .NET or do I leave them as is?

      Making changes to the case seems like a terrible idea since we’re dealing with case-sensitivity in both C# and Mongo…

      … but then again if you load some records from another database, cast it into a .NET type and then return the object to the database then you end up with double the properties since you now have two different cases for the same thing…

      So far I’ve been mulling over creating Interfaces (something like ICanBeCastIntoAMongoObjectDudes… not really…) or allowing attributes to be applied to property names that can let the developer define casing rules…

      Maybe I’m over thinking it but I’m always open to suggestions…

      hugoware

      March 17, 2010 at 10:17 pm

      • I would vote for the use of Attributes. Allows for more flexibility and no guesses on the library’s part.

        Andre'

        April 2, 2010 at 3:24 pm

      • I vote for Attributes as well.

        ActiveEngine Sensei

        April 2, 2010 at 3:36 pm

      • Whadaya’ think this is here? A democracy? 🙂

        Yeah, I think having a attributes is probably the most common method for handling this. I’ll see what I can do.

        Thanks for the feedback

        hugoware

        April 4, 2010 at 1:04 am

  5. […] a comment » I got some good questions earlier today about how to perform updates on records in CSMongo. Rather than doing a short answer in a comment I […]

  6. I’ve been researching a lot of drivers lately and while the others may be more “mature”, yours is the most intriguing! Thanks Hugo!

    Jason

    April 4, 2010 at 9:42 pm

    • I’ve just ranked this as the ‘best comment about CSMongo, ever’ – 🙂

      Thanks for the feedback!

      hugoware

      April 5, 2010 at 8:40 am


Leave a comment