Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using MongoDB with the Official C# Driver

0.00/5 (No votes)
24 Oct 2011 1  
Introduces how to use MongoDB in your ASP.NET MVC project using the official C# driver.

Introduction

MongoDB is an appealing applicant in NoSQL world, providing much support with drivers, comprehensive documents, and a considerably large community to build applications using NoSQL technology instead of going directly to RDBMSs such as MS SQL Server and Oracle.

In this article, I would like to describe how to use MongoDB with the official C# driver. There are a few alternatives to this driver, some of which are even considered better, providing extra features such as LINQ support, but I prefer using this driver in my projects because it is supported officially.

The code samples are taken from the demo project. I recommend you to examine the demo project because you will understand better and have the option to try MongoDB.

A few words about the MongoDB data structure

In MongoDB, the data structure and hierarchy are like:

Databases
   Collections
      Documents
         Fields

A field is a key-value pair. A key is a name (string). A value is a basic type like string, integer, float, timestamp, binary, etc., or a document, or an array of values.

In short, collections are made of JSON-like doc­u­ments. This is the biggest difference from traditional RDBMSa, so try to treat your data as they are real objects, not pure data. Also, you will see the classes starting with Bson in the official driver.

The definition of BSON from bsonspec.org is a bin­ary-en­coded seri­al­iz­a­tion of JSON-like doc­u­ments. BSON is designed to be lightweight, traversable, and efficient. BSON, like JSON, supports the embedding of objects and arrays within other objects and arrays.

Preparation

Firstly, download an appropriate MongoDB package from the following address and execute mongod.exe to start your MongoDB server.

If you have problems in starting your server related with paths, create a folder to store database files and start mongod.exe with the dbpath argument by giving the folder path as shown in the following line:

mongod.exe --dbpath "C:\data"

In order to use this driver, download the required assembly files from the following link:

This is the place where you can obtain the source code and download the setup package. When you download a proper package and install it, you will be able to find the following two assembly files under the path Program Files Folder\MongoDB\CSharpDriver 1.2. By the way, I used CSharpDriver-1.2.0.4274.msi in this article.

  • MongoDB.Bson.dll
  • MongoDB.Driver.dll

You need to add these two files as reference in your project. MongoDB.Bson.dll is for BSON serialization and the other is for database communication. Now, you are ready to develop your project using MongoDB.

Server startup

Firstly, you should make sure that MongoDB is running and you point to the port on which the server is running correctly. Below you see the output when you start the MongoDB server from the command line.

MongoDB server running

In the screen, the port is marked with a red box. Then, start the MongoDB console by running mongo.exe and run the following lines to create your database:

use MessageDB

Now you are finished with the MongoDB server.

Application

We would use these two namespaces to communicate with our MongoDB server and data to process, so add the following lines:

using MongoDB.Driver;
using MongoDB.Bson;

// Create server settings to pass connection string, timeout, etc.
MongoServerSettings settings = new MongoServerSettings();
settings.Server = new MongoServerAddress("localhost", 27017);
// Create server object to communicate with our server
MongoServer server = new MongoServer(settings);
// Get our database instance to reach collections and data
var database = server.GetDatabase("MessageDB");

In these lines, we create a server object and pass the required settings such as credentials, connection string, port, etc. In this example, we use localhost as the database server and 27017 as the server port. Then, we access the database, MessageDB, which we created before. With the database object, we are ready for CRUD operations.

Reading

var users = database.GetCollection("users").
                            FindAll().
                            SetSortOrder(SortBy.Descending("createdate"));

The official driver provides many ways to access and process the data. In the lines above, we first access the users collection in ordered form using the createdate value. It is also possible to access the collection or other compatible collections by indexing [] like datasase["users"].

foreach (var user in users)
{
    var userName = user["firstname"].AsString;
    ...
}

After we get the results, either in BSON or strongly typed object format, we can iterate over them.

It is possible to write complex queries using Query.

var query = Query.And(
                Query.Matches("firstname", BsonRegularExpression.Create("^e")),
                Query.GT("createdate", BsonValue.Create(DateTime.Now.AddDays(-7).Date)));

// Get all users whose firstname starts with 'e' and who are
// created within last 7 days in sorted format by createdate
var users = database.
                GetCollection("users").
                Find(query).
                SetSortOrder(SortBy.Descending("createdate"));

You can obtain the query transformed from objects to MongoDB notations by evaluation like this:

MongoDB query

Editing

When we get the data, we can edit the values directly and save the updated documents by calling the Save method of the relevant collection. In the following lines, we obtain a unique document by providing the ID value.

// Update user by id
var user = users.FindOneById(ObjectId.Parse(id));

user["firstname"] = userToEdit.FirstName;
user["lastname"] = userToEdit.LastName;
user["age"] = userToEdit.Age;

// Update user object
users.Save(user);

The ID value is a special type of field which is created by the database itself to provide uniqueness of each document, so it is possible to get the documents easily. The ID value actually contains a string value like 4ea41ac244b8681c3072b212, so it is easy to pass this value through each request.

The FindOneById method gets a BsonValue. In order to pass the ID value as BsonValue, we call ObjectId.Parse to obtain an appropriate format of BsonValue for ID values.

Lastly, we call Save to update the edited document.

Insertion

Adding new documents is much simple as editing them. You create a reference for the collection, create a new BsonDocument, and add it to the collection reference by calling insert.

// Get user collection reference
var users = database.GetCollection("users");

// Create BsonDocument object for new user
var user = new BsonDocument();
user["firstname"] = userToEdit.FirstName;
user["lastname"] = userToEdit.LastName;
user["age"] = userToEdit.Age;
user["createdate"] = DateTime.Now;

// Insert new user object to collection
users.Insert(user);

Dynamic schema

Up to now, we considered basic objects and dealt with CRUD operations on them. As you can see, we did not define any schema specific setting yet. When we set a value in BsonDocument, the field key is created automatically with the type of given value. In the following case, when we execute the following line:

user["age"] = 18;

The age key is created automatically and the type of the field would be Int32. You also have the option to check if the key exists by calling the Contains method of the object and making sure that it is compatible with a given type and will be cast properly, like:

if (user.Contains("updatedate") && user["updatedate"].IsDateTime)
{
    var updatedate = user["updatedate"].AsDateTime;
}

I mentioned dynamic schema and I want to make my user object more dynamic:

[HttpPost]
public ActionResult Index(string id, string newRemark)
{
    var users = database.GetCollection("users");
    var user = users.FindOneById(ObjectId.Parse(id));

    var remark = new BsonDocument().
                        Add("content", newRemark).
                        Add("date", DateTime.Now);

    if (user.Contains("remarks"))
    {
        user["remarks"].AsBsonArray.Add(BsonValue.Create(remark));
    }
    else
    {
        user["remarks"] = new BsonArray().Add(BsonValue.Create(remark));
    }

    users.Save(user);

    return RedirectToAction("Index", new { id = id });
}

In these lines, we change the structure of our user object. We propose the new data type, remarks.

First, we check if the user object already contains an element with the key remarks. remarks actually is an array which holds content and date values. If remarks exists, we cast it to an array and add a new remark. Otherwise, we create a new type of array and add the new remark to it. That's all. The output of the user object will be like this:

{ 
    "_id" : ObjectId("4ea51941073d601758138560"), 
    "firstname" : "ercan", 
    "lastname" : "anlama", 
    "age" : 26, 
    "createdate" : ISODate("2011-10-24T07:52:33.29Z"), 
    "remarks" : 
        [
            { 
                "content" : "this is my first remark", 
                "date" : ISODate("2011-10-24T07:53:22.511Z") 
            }
        ] 
}

Object serialization

The driver supports object serialization for documents. It means that you do not need to access the fields and values with string values, but strongly typed values. Let's see this in action.

We have two objects, User and Remark.

public class User
{
    public User()
    {
        Remarks = new List<Remark>();
    }

    public ObjectId id { get; set; }
    [BsonElementAttribute("firstname")]
    public string FirstName { get; set; }
    [BsonElementAttribute("lastname")]
    public string LastName { get; set; }
    [BsonElementAttribute("age")]
    public int Age { get; set; }
    [BsonElementAttribute("createdate")]
    public DateTime CreateDate { get; set; }
    [BsonElementAttribute("remarks")]
    public IList<Remark> Remarks { get; set; }

    public string GetFullName()
    {
        return String.Format("{0} {1}", FirstName, LastName);
    }
}

public class Remark
{
    [BsonElementAttribute("content")]
    public string RemarkContent;
    [BsonElementAttribute("date")]
    public DateTime Date; 
}

We use BsonAttributes to state which property in the object matches which field in BsonDocument. Also, mind that we define a special property which is the ObjectId type, to store ID values of BsonDocuments. If the property name is the same as the field key, you do not need to state any attribute as we did in the id property.

Here is how to implement this serialization:

var user = database.GetCollection("users").FindOneByIdAs<User>(ObjectId.Parse(id));

The driver employs the methods which end in As. In general, these methods serve to retrieve documents in strongly typed format. Therefore, we can keep the bridge between NoSQL data and object orientation.

Final words

I tried to introduce in this article what is MongoDB and how to use the official C# driver. Of course, these are the basic points, but the most commonly used functions of MongoDB, so it is larger than illustrated in this article. It offers powerful functionalities like GridFS and MapRedure, which you might need in some areas while developing your project with MongoDB.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here