Hugoware

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

Posts Tagged ‘CSMongo

Performing Updates With CSMongo

with 7 comments

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 figured a full post about it might be more helpful. While playing with this I made some changes to the code so if you have a previous version then you’re going to want to update to the newest version.

CSMongo has a couple ways available to update records right now. One is after you have made a selection from a database and the other is a query sent to the database.

Update After Selection

If you’ve used LINQ to SQL before then you know that you can load database objects into memory, modify them and then submit the changes and like magic your records are updated… maybe not *real* magic but I was still impressed the first time I saw it…

CSMongo allows for a similar approach when performing updates on documents loaded from the database. For example, here is how we could load a set of users, modify them and then issue back our changes.

//connect to the database
using (MongoDatabase database = new MongoDatabase(connectionString)) {

    //load a set of records
    MongoCollection collection = database.GetCollection("drivers");
    
    //select a set of records
    var drivers = collection.Find()
        .Greater("age", 16)
        .Select();

    //make some changes
    drivers.Apply(new {
        canDrive = true
    });

    //submit the changes
    collection.SubmitChanges();

}

This code load in a set of records and saves their reference to the collection (which is also managed by the MongoDatabase class in case you were wondering). This allows you to make changes to your object in multiple places and then call SubmitChanges to apply everything you’ve done.

When the record is first loaded a hash is created of the object which is used to check for changes which means that if you don’t change anything, or if values are set but not actually different then the update request is never sent.

It is also important to realize that MongoCollection.SubmitChanges() only sends updates for the collection that is called on whereas MongoDatabase.SubmitChanges() checks all of the collections that have been loaded and attempts to apply their changes. This is actually one of the advantages to using the MongoDatabase to create instances of your MongoCollection since it can automatically handle checking for changes.

In this last example we don’t actually use any of the information in the record which makes loading it into memory first rather pointless which leads us into the next type of update.

Immediate Updates

Sometimes when you want to change records you don’t want to have to load them first. Sometimes you simply want to perform and update for a bunch of matching records that meet a certain condition. In that instance you can issue an update immediately from a MongoQuery.

The example we used above is a good example where sending an update would be better than loading the records first. There isn’t a lot that changes but what happens in the background is much different.

//connect to the database
using (MongoDatabase database = new MongoDatabase(connectionString)) {

    //issue the query directly from the database level
    database.From("drivers")
        .Greater("age", 16)
        .Set(new {
            canDrive = true
        });

}

You can also perform an update directly from the MongoCollection by using the Find() command, which starts a MongoQuery that can be used for the update.

You may notice that this example doesn’t have a call to SubmitChanges() in it — That’s because when I say immediate then by golly, I mean right away! In fact, if I remember correctly ever command on the MongoDatabase level is evaluated immediately.

Anyways, CSMongo is still early in development so if anyone has some additional ideas how to handle these updates then I’m certainly interested in what you think.

Written by hugoware

March 17, 2010 at 10:04 pm

CSMongo – An Introduction

with 3 comments

Last night I did a short screencast explaining the basics of using Documents in CSMongo. The screencast goes over adding, changing and removing values along with getting access to the values you assign.

Written by hugoware

March 5, 2010 at 9:29 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