MongoDB Console Tip: Better Display of Object on Console

Quick tip. This is just a neat way to better display the JSON from the console. For example, if I did this in one of my dbs:

db.client.find()

I would get:

{ "_id" : ObjectId("4da45b3cf980ed161462c2ef"), "ContactEmergencyDetails" : { "awesome" :
[ 1111, 2222, 3333 ], "cool" : "awesome", "dan" : [ 4.5, 5.322 ] }, "firstname" : null, "lastname" : null }

But if I changed it to this (converting it to Array):

db.client.find().toArray()

It formats it better:

[
  {
    "_id" : ObjectId("4da45b3cf980ed161462c2ef"),
    "ContactEmergencyDetails" : {
      "awesome" : [
                    1111,
                    2222,
                    3333
                ],
        "cool" : "awesome",
        "dan" : [
                  4.5,
                  5.322
                ]
  },
  "firstname" : null,
  "lastname" : null
  }
]

Getting Started with the MongoDB C# Driver

Here’s my attempt on writing a super-barebones tutorial for using the MongoDB C# Driver. It’s a very hands-on tutorial-by-example, showing you the basics of the driver by creating console apps.

I’m assuming you’ve installed the official MongoDB C# driver and read the intro. Heads up on how you set up the driver. The .msi sets it up in the GAC. The zip file has the assemblies that can just be referenced in your project.

After you’ve done those two things, you can proceed. 🙂

Dependencies

In projects, you have the option of utilizing the following namespaces:

using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Bson.Serialization.IdGenerators;
using MongoDB.Bson.Serialization.Options;
using MongoDB.Bson.Serialization.Serializers;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using MongoDB.Driver.Wrappers;

The most commonly used are Bson, Driver, Serialization, and Serialization.Attributes. This tutorial will use these four in all code samples, so make sure you include them in your app, even if I don’t have it in the code samples. You can learn more about the API/namespaces by checking out the docs.

Connecting to a MongoDB Database

Connecting is pretty simple. Once you include the C# driver assemblies, you connect as follows:

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
    }
  }
}

That’s pretty much all you need to connect. Of course, I recommend putting the connection string in the Web.config, or some initializer.

Inserting a document on MongoDB

There are tons of ways to do this, but one of the simplest ways is to create a class, create an instances of that class, and pass it into a MongoDB object that serializes that object into BSON and submits it to your database.

So for this example, before inserting a document into the database from C#, one has to do two things (aside from the establishing a connection and choosing which db to write to):

  1. Create a Generic Collection object. In this case, it’s a MongoDB collection.
  2. Create a class that’s to be used by the Generic Collection.

Those two go together.

Also, note that while working with MongoDB in C#, the word “collection” may be thrown around loosely. In MongoDB you have a “Collection” that’s comparable to a Table in a traditional ER database. A MongoDB “Collection” holds “documents,” which is comparable to a “record” in a traditional ER database. On the opposite side, in C#, a collection is a data structure that unlike an Array, can be resized dynamically and is more flexible as far as functionality.

The MongoDB Generic Collection is a C# collection that can hold any type of object, but it has to know what type of object it’s holding. You let it know what kind of type by creating a class, and then when you create a collection, you specify the name of the class. So for example, this is the syntax for creating a Generic Collection that has Car objects (where person is defined in a class):

After that line of code, you populate the vehicles object (remember it’s a MongoDB Generic collection that holds Cars objects), by calling the method “GetCollection” from the Cars object we creating in the last section “Connecting to a MongoDB database”:

In the above statement, if MongoDB does not find a collection on the database called “vehicles,” it will create it for you.

What does that Cars class look like? Pretty simple:

  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
  }

Then of course, before sending it to the MongoDB database, you create an object and set the values of the object:

      Cars newCar = new Cars();
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;

And then insert it in MongoDB:

vehicles.Insert(newCar);

To put it in perspective, here’s the entire program:

namespace ConsoleApplication1
{
  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
  }
 
  class Program
  {
    static void Main(string[] args)
    {       
 
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection vehicles;
 
      vehicles = Cars.GetCollection("vehicles");
 
      Cars newCar = new Cars();
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;      
 
      vehicles.Insert(newCar);
    }
  }
}

The insert method should serialize the Cars object (newCar) and create the MongoDB document, mapping the properties of the Cars class to MongoDB document key-pair values.

Let’s see how this got created in our database:

Run:

db.vehicles.find()

(e.g. ignore the lname property. This was removed in the source code)

Inserting Complex Objects in MongoDB

Let’s try inserting an object with a more complex data structure. Let’s assume we have the following class:

  public class Cars
  {
    public string _id { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }

Now let’s declare the class and its properties:

      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;
 
      newCar.history = new Hashtable();   
      newCar.history.Add("2010-08-14", "Puss 'N Boots");
      newCar.history.Add("2011-12-01", "Puff the Magic Dragon");
      newCar.history.Add("2009-03-07", "Fraggle Rock");      
 
      newCar.magicNumbers = new int[3];
      newCar.magicNumbers[0] = 60;
      newCar.magicNumbers[1] = 186000;
      newCar.magicNumbers[2] = 1440;
 
      newCar.complex = new Hashtable();
      newCar.complex.Add( newCar.magicNumbers[1], newCar.history );
      newCar.complex.Add( System.Guid.NewGuid().ToString(), newCar.history);

It outputs the following (formatted for better reading):

{
  "_id": "a07513c8-9cb5-46cd-a9cb-425cabc0dd76",
  "brand": "Honda",
  "lname": null,
  "miles": 186000,
  "age": 1,
  "history": 
  {
    "2010-08-14": "Puss 'N Boots",
    "2009-03-07": "Fraggle Rock",
    "2011-12-01": "Puff the Magic Dragon"
  },
  "complex": 
  [
    ["eb7b3d4d-87b1-43c1-9fe7-5a5e4b5b79de",
    {
        "2010-08-14": "Puss 'N Boots",
        "2009-03-07": "Fraggle Rock",
        "2011-12-01": "Puff the Magic Dragon"
    }],
    [
    186000,
    {
        "2010-08-14": "Puss 'N Boots",
        "2009-03-07": "Fraggle Rock",
        "2011-12-01": "Puff the Magic Dragon"
    }]
  ],
  "magicNumbers": [60, 186000, 1440]
}

Now let’s look at the entire code for all this:

namespace ConsoleApplication1
{
  public class Cars
  {     
    public string _id { get; set; }   
    public string brand { get; set; }  
    public string lname { get; set; }  
    public Int32 miles { get; set; }  
    public int age { get; set; }
 
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }
 
  class Program
  {   
    static void Main(string[] args)
    {
 
      MongoServer  server = MongoServer.Create("mongodb://work2");          
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection<Cars> vehicles;
 
      vehicles = Cars.GetCollection<Cars>("vehicles");
 
      Cars newCar = new Cars();
 
      newCar._id = System.Guid.NewGuid().ToString();
      newCar.brand = "Honda";
      newCar.miles = 186000;
      newCar.age = 1;
 
      newCar.history = new Hashtable();   
      newCar.history.Add("2010-08-14", "Puss 'N Boots");
      newCar.history.Add("2011-12-01", "Puff the Magic Dragon");
      newCar.history.Add("2009-03-07", "Fraggle Rock");      
 
      newCar.magicNumbers = new int[3];
      newCar.magicNumbers[0] = 60;
      newCar.magicNumbers[1] = 186000;
      newCar.magicNumbers[2] = 1440;
 
      newCar.complex = new Hashtable();
      newCar.complex.Add( newCar.magicNumbers[1], newCar.history );
      newCar.complex.Add( System.Guid.NewGuid().ToString(), newCar.history); 
 
      vehicles.Insert<Cars>(newCar);         
 
      Console.ReadLine();                
    }     
  }
}

Reading the 1st MongoDB document from the database

Before you query the database, you must make sure the class and member types match the values/objects that the MongoDB connection will return.

Let’s try to fetch the 1st document. To see what we’re expecting, let’s fetch it via the console first:

db.vehicles.find().limit(1)

which returns:

{
  "_id" : ObjectId("4d95f30058430000007a5943"),
  "ObjectId" : ObjectId("000000000000000000000000"),
  "brand" : "Ford",
  "lname" : null,
  "miles" : 2500,
  "age" : 1
}

Now that we know what it returns, let’s make sure we have the class in place that will handle the kind of key-value pairs in the MongoDB collection:

  public class Cars
  {
    public MongoDB.Bson.ObjectId _id { get; set; }
    public MongoDB.Bson.ObjectId ObjectId { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    // Complex Properties
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }

Notice that the properties history, complex, and magicNumbers are not part of the MongoDB document we queried. That’s OK. The MongoDB C# drivers are smart enough to map to to a null value when deserializing from MongoDB to a C# object.

Now how do you map values from a MongoDB connection to a C# object? Like so:

    Cars car = vehicles.FindOne();

The FindOne() method will return the first document. Now let’s add some context to this line of code, by adding MongoDB connection code (that we established before), writing it to the screen, and checking for nulls in the complex properties:

namespace ConsoleApplication1
{
  public class Cars
  {
    public MongoDB.Bson.ObjectId _id { get; set; }
    public MongoDB.Bson.ObjectId ObjectId { get; set; }
    public string brand { get; set; }
    public string lname { get; set; }
    public Int32 miles { get; set; }
    public int age { get; set; }
 
    // Complex Properties
    public Hashtable history { get; set; }
    public Hashtable complex { get; set; }
    public int[] magicNumbers { get; set; }
  }
 
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase Cars = server.GetDatabase("Cars");
 
      MongoCollection vehicles;
      vehicles = Cars.GetCollection("vehicles");
 
      Cars car = vehicles.FindOne();
 
      Console.WriteLine(car._id);
      Console.WriteLine(car.ObjectId);
      Console.WriteLine(car.brand);
      Console.WriteLine(car.lname);
      Console.WriteLine(car.miles);
      Console.WriteLine(car.age);
 
      if (car.history == null)
        Console.WriteLine("history was null");
      else
        Console.WriteLine(car.history);
 
      if(car.complex == null)
        Console.WriteLine("complex was null");
      else
        Console.WriteLine(car.complex);
 
      if (car.magicNumbers == null)
        Console.WriteLine("magicNumbers was null");
      else
        Console.WriteLine(car.magicNumbers);                  
 
      Console.WriteLine("ha made it this far!");
      Console.ReadLine();
    }
  }
}

This will print the following on to the screen:

Read All Documents from a MongoDB Collection

Let’s try to output all the documents from a collection. We’re going to create a new MongoDB collection under the Cars database. Through the MongoDB client, we’ve created four documents. Let’s read them from the console first:

db.bankaccount.find()

The four documents look like:

{ "_id" : ObjectId("4d9650301b6e000000004116"), "name" : "Batman" }
{ "_id" : ObjectId("4d9650391b6e000000004117"), "name" : "Spider-Man" }
{ "_id" : ObjectId("4d96503f1b6e000000004118"), "name" : "Superman" }
{ "_id" : ObjectId("4d9650431b6e000000004119"), "name" : "Spawn" }

So the first thing is to create a class that represents each MongoDB document:

public class BankAccount
  {
    public MongoDB.Bson.ObjectId _id;
    public string name;
  }

The class is used to create an object that will contain the data that is deserialized (from MongoDB to a C# object).

Here’s the code to query all documents, iterating through them and showing them on the screen:

      MongoCursor cursor = BankAccountCollection.FindAll();
 
      foreach (BankAccount ba in cursor)
      {
        Console.WriteLine(ba._id);
        Console.WriteLine(ba.name);
        Console.WriteLine("=============================");
      }

Looks straightforward enough. What is a cursor? We can think of a MongoDB Cursor as a DataSet in .NET. Later, we’ll see MongoDB Queries, which resemble a SqlCommand object in .NET. Queries are configurable objects to search for document data. The Query object is then passed into the a find method (there are several) of the MongoCollection. The find method then typically returns a Cursor, which is then iterated through. (More about this later.) Also note that a Cursor is not “populated” with documents until the there’s an attempt to retrieve the first result from the server.

Let’s see the entire program in action.

namespace ConsoleApplication1
{
  public class BankAccount
  {
    public MongoDB.Bson.ObjectId _id;
    public string name;
  }
 
  class Program
  {
    static void Main(string[] args)
    {
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase BankAccountDatabase = server.GetDatabase("Cars");
 
      MongoCollection BankAccountCollection;
      BankAccountCollection = BankAccountDatabase.GetCollection("bankaccount");
 
      MongoCursor cursor = BankAccountCollection.FindAll();
 
      foreach (BankAccount ba in cursor)
      {
        Console.WriteLine(ba._id);
        Console.WriteLine(ba.name);
        Console.WriteLine("=============================");
      }      
 
      Console.WriteLine("\n\nha made it this far!");
      Console.ReadLine();
    }
  }
}

The above program outputs the following:

If we wanted to retrieve a specific query, rather than doing this (from the above code):

 MongoCursor cursor = BankAccountCollection.FindAll();

We would do:

      var query = Query.EQ("name", "Batman");
      var cursor = BankAccountCollection.Find(query);

One last thing to mention about the Find() method, as stated from docs:
The Find method (and its variations) don’t immediately return the actual results of a query. Instead they return a cursor that can be enumerated to retrieve the results of the query. The query isn’t actually sent to the server until we attempt to retrieve the first result (technically, when MoveNext is called for the first time on the enumerator returned by GetEnumerator). This means that we can control the results of the query in interesting ways by modifying the cursor before fetching the results.

Get only key-value pairs from a collection

In this example, we’re going to try to do something like this in SQL:

SELECT Column1, Column2
FROM  TABLE

We’re also going to be using the collection “bbu”. Let’s try to translate this query:

db.bbu.find({},{whichAPI:1}).limit(10)

Which would return the following:

{ "_id" : ObjectId("4d90fbd85843000000004359"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435a"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435b"), "whichAPI" : "SIT" }
{ "_id" : ObjectId("4d90fbd8584300000000435c"), "whichAPI" : "SL" }
{ "_id" : ObjectId("4d90fbd8584300000000435d"), "whichAPI" : "SL" }

First, we’re going to define the class. We’re going to establish all the properties that are needed for a class, but then only query and populate two colums from the class.

Define the class and all of its properties.

public class BBU
  {
    public MongoDB.Bson.ObjectId _id;
    public int counter;
    public string whichAPI;
  }

Now the actual program:

  class Program
  {
    static void Main(string[] args)
    {    
 
      MongoServer  server = MongoServer.Create("mongodb://work2");
      MongoDatabase BBUDatabase = server.GetDatabase("bbu");
 
      MongoCollection BBUCollection;
      BBUCollection = BBUDatabase.GetCollection("bbu");
 
      MongoCursor cursor = BBUCollection.FindAll().SetFields("id","whichAPI").SetLimit(5);
 
      foreach (BBU ba in cursor)
      {
        Console.WriteLine(ba._id + "----" + ba.whichAPI);
        Console.WriteLine("=============================");
      }      
 
      Console.WriteLine("\n\nha made it this far!");
      Console.ReadLine();                        
 
    }
  }

In the example above, SetLimit(5) will only return the top 5 documents.

Conclusion

I hope you got a good a sense of the basics of using the MongoDB C# driver. I’ve only scratched the surface of the API. I’ll be discussing more advanced topics in future posts.

For the meantime, I point you to the MongoDB Google Group: http://groups.google.com/group/mongodb-user?pli=1 where you’ll get informative responses, usually very quickly.

I also recommend you following the following folks on Twitter and these blogs/sites:

Lastly, I recommend you check out the MongoDB video presentations using the C# Driver and working in a Microsoft environment.

Checklist to Consider Before Migrating from SQL Server to NoSQL

Here’s a checklist of items to consider before migrating to a NoSQL db from SQL Server. If you come from SQL Server land, you may be used to these features and facilities. So before shifting over to a different world, consider if the db you’re jumping into (MongoDB, CouchDB, etc.) meets your needs by analyzing these items. Keep in mind that some features may not exist in NoSQL, not because of immaturity, but because it may not apply to the nature of a NoSQL database.

Handle Load

Compare against SQL Server:

Reading

Writing

Resource Monitoring

CPU Usage

Memory Use

Disk use

Transactions

Are there software design patterns to rollback

Locking

Reading

Programming

Syntax

SELECT / UPDATE / DELETE / INSERT / JOINS

Reusable Code Modules

Compiled Stored procs

Functions

Custom Data Types

Dynamic Management Views

Indexing

Clustered

Non-Clustered

Toolset / Resources

IDE

Administration

Profiler

Excution Planner

Community

Books

Administration

Complexity

Backing up

Full

Differentials

Transaction Log

Recovery

Replication / Clustering

Snapshots

Security

C# Integration

Facilities

Full Text Search

Snapshots

Kooboo CMS First Impressions

Kooboo is a CMS based on ASP.NET MVC. Recently, I got a chance to take it for a spin, and here are some of my thoughts. Keep in mind that the drawbacks here may come just from my ignorance of the tool use. 🙂 I’ll update this as the more I learn about the inner workings.

Benefits

  • Admin Panel’s UI is intuitive for designers/programmers
    • Easy to add pages
    • Easy to add your own themes/styles
    • Easy to create your own type of content
    • Easy to add content
  • Lots of Features, more than Orchard
  • Mature, has been around for a while (2008)
  • Views are coded in Razor
  • Can connect to MongoDB and other datasource types
  • Versioning of any piece of content and view differences
  • Manage website resources easily – images/documents/etc.

Drawbacks

May not be a drawback once I figure out the “how” and get better understanding.

  • Once a site is created, when I migrated from XML to MongoDB, I lost all the website data from the XML files.
  • Admin Panel’s UI may not be intuitive to non-designers/programmers.
  • Site directory structure Kooboo generates is not the same as the traditional ASP.NET MVC.

Let’s take a look. For a site I created using Kooboo, named “batman”:

  • When a content type is created, it does not create a C# class file. (I didn’t see one at least, in the directory structure.) It does, however, create a MongoDB collection for the content, there’s just no C# class mapped to it.
  • There’s no clear way to bind a View to a model class as in traditional ASP.NET MVC since, Kooboo doesn’t create a C# class file. It doesn’t follow the traditional file/folder naming convention: for each View, you map that to a model.
  • Community not as large as other CMS communities (Orchard, Umbraco, DNN).

I’ll keep exploring, but this is what I’ve found so far.

Kooboo Setup Notes

I had to apply these settings to make Kooboo work on my machine connecting to MongoDB on my VM:

In Web.config:

For the MongoDB.config (when you follow the instructions to set it up http://www.kooboo.com/Documents/Detail/CMS/v3/MSSQL-SQLCE-RavenDB-and-MongoDB ), I copied it to:

Kooboo_CMS/

And you may have to copy it to C:\kooboo\Kooboo_CMS\Kooboo_CMS\bin as well. (my installation was a little flaky)

You’ll have to build the project (in VS2010) if you already ran the site (the default data store is XML files).

When all is set and done, make sure that the db was created on MongoDB. In this case, it created the db samplesite.

NULLs in MongoDB

By default, the C# driver’s serializer takes a null value and assigns a default, rather than just writing the word NULL in the collection when inserting.

So if you had a an object that had 50 properties, only set 1 value in it, and passed it to MongoDB, it would insert all 50 properties, which would be wasteful (depending on how you looked at it).

One can decorate the property with the [BsonIgnoreIfNull] attribute and will not write that element to the db if it’s null. However, if you don’t always want to use this property, one can set it once (and forget it) by creating a MongoDB “ConventionProfile” across the entire application. We have this setup in the Global.asax.cs so it gets created when the application is loaded:

var profile = new ConventionProfile(); 
profile.SetIgnoreIfNullConvention(new AlwaysIgnoreIfNullConvention()); 
BsonClassMap.RegisterConventions(profile, t => true);

However, even with that, it only appears that it does this only for strings that are null. If you have a property that’s Boolean, Integer, or Date, it will still write the elements to the database, setting Booleans to Falses, Integers to 0, and Dates to an ISO timestamp. It does this partly because these data types don’t implement a NULL property, so they can’t be null. To “make” them NULL, you have to use the question mark after the data type, like so:

bool? IsEnabled;
int? MagicNumber;
Date? TimeStamp;

All three are short for:

Nullable<bool> isEnabled;
Nullable<int> MagicNumber;
Nullable<Date> TimeStamp;