Hugoware

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

Posts Tagged ‘Driver

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

CSMongo Driver – Part 1

with 8 comments

My new project CSMongo, a Mongo driver for .NET, is now online! Check it out!

Lately, I’ve been spending a lot of my time writing a driver for Mongo in C#. The primary goal was to make it comfortable to work with dynamic objects in a static language — which is a project I’ve worked on before in the past.

I still have a lot of code to write but I’m getting close to a working version that I can get out the door. This post discusses how my Mongo driver works currently works.

Dynamic In Static-Land

The next version of .NET introduces the dynamic keyword but until then I needed to build a class that worked with C# and was dynamic enough to work with Mongo. The main hurdle is that a ‘dynamic’ isn’t just a dictionary of key/value pairs. Instead, an object can be nested several level deep.

Additionally, data types between static languages and dynamic languages are also handled differently. Think about numbers for a second. In C# you have single, double, float, decimal, etc. – But Javascript? Yeah, you have Number — A heck of a lot easier to deal with but can cause problems when trying to pull a value back out of your object.

Below are some samples how you can create Mongo document with this driver.


//Creating And Assigning Vaues
//===============================
MongoDocument document = new MongoDocument(new {
	name = "Hugo",
	age = 29,
	admin = true
	});
	
//make changes and assign new values using +=
document += new {
	age = 30,
	settings = new {
		color = "red",
		width = 700
	},
	permissions = new string[] {
		"read", "write", "delete"
	}
};

//make changes using the path to a field
document["name"] = "Hugoware";
document["settings.color"] = "blue";

//or create new objects entirely
document["settings.urls.favorite"] = "http://hugoware.net";

//remove fields using -= and a string or string array
document -= "name";
document -= "settings.color";

//or remove multiple items
document -= new string[] { "age", "permissions" };

//also use typical methods to perform same changes
document.Set("name", new {
	first = "Hugo",
	last = "Bonacci"
});

document.Remove("settings", "name", "age");


//Merging multiple documents
//===============================

MongoDocument first = new MongoDocument();
MongoDocument second = new MongoDocument(new {
	name = "Hugo"
});

//merge either of the two ways listed
first += second; /* or */ first.Merge(second);
string name = first["name"]; // "Hugo"

This class allows for a lot of flexability to write to an object and make changes to it without needing to know about the object.

Going back to data types, each object has a value handler that manages working with the type and performing conversions. You are also able to provide a default value in case the property requested doesn’t exist or can’t be converted.

Here are a few more examples of accessing values types.

//Accessing Typical Values
//===============================

//create an empty object and access not real values
MongoDocument document = new MongoDocument();

//accessing by default property returns an object
//NOTE: Using Get() is better for accessing values
int a = (int)document["not.real"]; // *crash* null
int? b = document["not.real"] as int?; // null

//accessing by Get<T>() returns default(T)
int c = document.Get<int>("not.real"); // 0

//or define a fallback value
int d = document.Get<int>("not.real", 55); // 55

//next examples are assigned '54.342' which defaults to 'double'
document.Set("value", 54.342");

//access by default property
double e = (double)document["value"]; // 54.342

//or use the Get method that allows a cast request type
double f = document.Get<double>("value"); // 54.342
int g = document.Get<int>("value"); // 54
bool h = document.Get<bool>("value"); // true
string i = document.Get<string>("value"); // "54.342"

//Accessing Uncommon Values
//===============================

doc["count"] = long.MaxValue;
int a = (int)doc["count"]; // *crash*
int b = doc.Get<int>("count"); // 0
long c = doc.Get<int>("count"); // 0
long d = doc.Get<long>("count"); // 9223372036854775807

doc["count"] = uint.MaxValue;
uint e = doc.Get<uint>("count"); // 4294967295
long f = doc.Get<long>("count"); // 4294967295
decimal h = doc.Get<decimal>("count"); // 4294967295
int g = doc.Get<int>("count", int.MaxValue); // 0 (no default!)

As you can see there are a lot of different ways data types like this could play out. Failed conversions tend to be easier to detect than incorrect conversions. I suspect this will improve over time.

If you don’t like the way conversions are handled for a certain type, or if you have a custom class you want special rules created for, can define your own custom DataTypes that handle the formatting, parsing and saving to the database.

Database Queries

If you’ve grown accustomed to SQL queries then you’re going to be in a world of hurt with Mongo. They make sense after a bit of time but not like the somewhat human-readable format of a standard SQL query.

In this driver I’ve attempted to to make a LINQ-ish style query builder. This builder is used in a variety of places depending on the purpose (such as selection as opposed to updating).

Here are some query examples.

MongoDatabase database = new MongoDatabase("100.0.0.1", "website");

//simple chained query
database.From("users")
    .Less("age", 50)
    .EqualTo("group", "admins")
    .Select();

//anonymous types for parameters
database.From("users")
    .In("permissions", "write", "delete")
    .Select(new {
        take = 30
    });

//updating without a record using a
//query selector and update arguments
database.From("users")
    .Match("name", "^(a|b|c)", RegexOptions.IgnoreCase)
    .Update(new {
        enabled = false,
        status = "Disabled by Admin"
    });

Mongo queries appear to be missing several pretty important features that might make it a little more difficult for you to find records. I figured out how to use jLinq directly within Mongo so I’m going to see if version two might include a little jLinq supportHow cool would that be?

I’m hoping I’ll have the first version of my driver released sometime this week so check back for more news on the progress!

Written by hugoware

February 21, 2010 at 10:31 pm