Advanced MongoDB Queries in C# using the NoRM Driver: Part 1

In my last two posts, I said that I planned on showing how to perform more advanced queries using MongoDB. Today I will be doing just that by demonstrating advanced queries using the NoRM driver. The queries you learn here are not specific to the C# NoRM driver. I will show you three forms of each query: (1) the Json version and (2) the NoRM driver version in C# using Anonymous objects, and (3) How to use Linq with the NoRM driver.

Note, the source code for all these examples can be found here on GitHub.

Without further ado, lets jump in.

Conditional Operators: <, <=, >, >=

Native MongoDB Json

To apply conditional operators, we use the following operators:

> $gt Greater than
>= $gte Greater than or equal to
< $lt Less than
<= $lte Less than or equal to

The operator is combined with its comparison value is a single Json object in place of the value for the field. For instance:

db.orders.find( { OrderAmount : { $gt : 50 } } );

The above finds all orders with an amount greater than 50. Notice the pattern { $gt : 50 } which is { $operator : value } is used as the value for OrderAmount. You will see this pattern repeated for many of the advanced queries.

Here are all the operators:

db.orders.find( { OrderAmount : { $gt : 50 } } );
db.orders.find( { OrderAmount : { $gte : 50 } } );
db.orders.find( { OrderAmount : { $lt : 100 } } );
db.orders.find( { OrderAmount : { $lte : 100 } } );

C# NoRM Driver

Using Anonymous Objects

To do this using the NoRM driver, you can either use LINQ, or query using anonymous objects. For those using anonymous objects, NoRM provides a static class named Q to build queries from. So you can use Q.GreaterThan(value) to build the query. Below are the same queries using NoRM in C#.

var result1 = collection.Find( new {OrderAmount = Q.GreaterThan( 50 )} );
var result2 = collection.Find( new {OrderAmount = Q.GreaterOrEqual( 50 )} );
var result3 = collection.Find( new {OrderAmount = Q.LessThan( 100 )} );
var result4 = collection.Find( new {OrderAmount = Q.LessOrEqual( 100 )} );

Using Linq

Using Linq is pretty straightforward so I won’t show but one of the operations here:

var provider = new MongoQueryProvider(mongo);
var orders = new MongoQuery< Order >( provider );
var result1 = from order in orders
              where order.OrderAmount > 50
              select order;

Between Operation

Json

To perform a between operation, simply combine two of the above operators.

db.orders.find( { OrderAmount : { $gt : 50, $lt : 200 } } );

This finds orders where the order amount is between 50 and 200.

NoRM

Anonymous

For the NoRM driver, we use the And() method.

var result = collection.Find( new {OrderAmount = Q.GreaterThan( 50 ).And(Q.LessThan( 200 ))} );

Linq

var result = from order in orders
             where order.OrderAmount > 50 && order.OrderAmount < 200
             select order;

Not Equal To

Json

db.orders.find( { OrderAmount : { $ne : 100.23 } } );

NoRM

Anonymous

var result = collection.Find( new {OrderAmount = Q.NotEqual( 100 )} );

Linq

var result = from order in orders
             where order.OrderAmount != 100
             select order;

In Operator

Json

db.orders.find( { CustomerName : { $in : ["Elmer Fudd", "Daffy Duck"] } } );

NoRM

Anonymous

var result = collection.Find( new {CustomerName = Q.In( "Elmer Fudd", "Daffy Duck" )} );

Linq

To use the IN operator with Linq, you first need to create a List<T> of the “in” items to compare against. Then us the Contains() method to see if the item exists.

var result = from order in orders
             where new List {"Elmer Fudd", "Daffy Duck"}.Contains( order.CustomerName )
             select order;

Note that I initially tried to do this by creating an array and use contains, but this failed. You must create a generic list to get it to work.

Conclusion

Well this concludes Part 1 of the advanced queries. We’ll dig even deeper next time.

Note, the source code for all these examples can be found here on GitHub.

-Chris

Posted in .NET, C#, MongoDB, NoSQL | Tagged , , , | 6 Responses

Using MongoDB with the NoRM driver

This week we look at using strongly typed C# classes to access a MongoDB database using the NoRM C# driver.

The Driver

The NoRM driver differs from the MongoDB-CSharp driver we looked at last time in that it uses C# classes directly rather than the Document class. It automatically serializes and deserializes your classes to and from JSON. Using it is very similar to using NHibernate or another ORM…hence the name…NoRM.

You can get the driver at: http://github.com/atheken/NoRM

Referencing the driver

To use the driver, simply add a reference to it in your project. For this example, we’ll create a new console app to test out the driver. Add a reference just like you did in the previous example, but this time, you will reference the Norm.dll assembly.

image

The class to persist

We need a class to represent the data we want to persist in the db, so we will create an Order class.

public class Order
{
	public ObjectId ID { get; set; }
	public double OrderAmount { get; set; }
	public string CustomerName { get; set; }
}

This is simple enough.  Now lets look at using the driver.

Connecting the the db

To connect to the database with the NoRM driver, you need to provide the database name, the url, and the port number. Optionally, you can pass in security credentials. In our case, we are not using security, so I just passed in a string.Empty.

var mongo = new Mongo( "myorders", "localhost", "27017", string.Empty );
// For Linq to work, collection name must match Class name.
MongoCollection< Order > collection = mongo.GetCollection< Order >( "Order" );

Getting a reference to the collection

Next we need to get a reference to the collection we want to use. Collections in MongoDB are like tables in an SQL database. To get the collection we call the GetCollection() method on the database. Its a generic method and the generic parameter you pass to it is the type of object stored in that collection.

// For Linq to work, collection name must match Class name.
MongoCollection< Order > collection = mongo.GetCollection< Order >( "Order" );

As a side-note, I found that to get Linq to work correctly, the collection name had to be the same as the class name, but that is beyond the scope of this post. We’ll look at the Linq capabilities of this driver next week.

Inserting a new object into the db

They could not have made it much simpler to insert a new object using this driver. No real explanation is required here.

// Create a new order.
var order = new Order()
            	{
            		OrderAmount = 57.22,
            		CustomerName = "Elmer Fudd"
            	};

// Add the new order to the mongo orders collection.
collection.Insert(order);

The driver handles serializing the order and saving it. One line does it all.

Querying the db

To issue a query, we have two options, we can either create an order object with the properties we want to match on, or we can simply create an anonymous object. Anonymous objects are a bit easier to work with since you don’t have to worry about required properties or default values getting in the way.

Order result = orders.FindOne(new {CustomerName = "Elmer Fudd"});

The FindOne() method on the collection will return a single object. If no object is found, it will return the default value for the collection type.

Updating a document

To update a document, we can either query the object, modify it, and save it; Or we can perform an atomic update on only the fields we want to change. We’ll quickly look at both.

First, here is the query and save code.

// Get the order to change.
var orderToUpdate = orders.FindOne( new {CustomerName = "Elmer Fudd"} );

// Make the change.
orderToUpdate.OrderAmount = 1000000.00;

// Save the changed order.
orders.Save( orderToUpdate );

This is pretty simple. Lets look at updating only a single field atomically…

// Update the OrderAmount.
orders.Update(
		new {CustomerName = "Elmer Fudd"},
		x => x.SetValue( order => order.OrderAmount, 1000000.00 ) );

Here in one statement, we tell MongoDB to update all Orders for customer named Elmer Fudd to be $1,000,000. This statement only modifies that one field. Notice that the code new {CustomerName = “Elmer Fudd”} is the “selector”. That is, the “where clause” of our update statement. Any documents matching the selector will have the SetValue() applied to them.

Well, that’s about all for this week. We’ll probably look into more complex queries next week.

-Chris

Posted in .NET, C#, MongoDB, NoSQL | Tagged , , , | 1 Response

Code from my “Introduction to MongoDB” talk posted on github.

I have posted the code from my “Introduction to MongoDB” talk at the Austin Code Camp 2010 up on github. You can get it here.

Posted in .NET, C#, MongoDB, NoSQL | Tagged , , , | 1 Response

Slides from my MongoDB presentation at Austin Code Camp 2010

I gave a presentation at the Austin Code Camp 2010 entitled “Introduction to MongoDB”. The talk went really well, and there were far more people there than I expected. I recorded the talk with both a camcorder, and Camtasia…both of which failed for some reason. So all i have is the slides. Here they are:

I will be giving the talk again at BancVue for the developers so I will attempt to record it again then.

Posted in .NET, C#, MongoDB, NoSQL, Presentations | Tagged , , , , | 2 Responses

JetBrains dotCover code coverage tool for .NET now in early access

JetBrains has opened the dotCover Early Access Program. dotCover is JetBrains’ new code coverage tool for .NET. Here are some of the features (taken from the JetBrains website).

  • Calculates statement-level coverage of .NET 1.0-4.0 applications
  • Integrates with Visual Studio 2005, 2008 and 2010
  • Integrates with ReSharper to show test coverage
  • Highlights uncovered code in Visual Studio
  • Shows which tests cover particular piece of code
  • Shows coverage of Silverlight applications

After having many difficulties with NCover over the years, I am really excited to use this product.

-Chris

Posted in .NET, Tools | Tagged , , , | Leave a comment