Codementor Events

Working with MongoDB in .NET (Part 1): Driver Basics & Inserting Documents

Published Nov 23, 2016Last updated Jan 18, 2017
Working with MongoDB in .NET (Part 1): Driver Basics & Inserting Documents

MongoDB, classified as a NoSQL database, is a document-oriented database system which stores data in JSON-like format. MongoDB represents JSON documents in a binary-encoded format called BSON behind the scenes, and the MongoDB BSON implementation is lightweight, fast, and highly traversable. This means that MongoDB gives users the ease of use and flexibility of JSON documents together with the speed and richness of a lightweight binary format.

In this tutorial series, I'll show you how to work with MongoDB in your .Net applications using the CRUD functions available from the .Net driver. MongoDB drivers allows you to work with MongoDB from different programming language. In this tutorial series, we'll be working with the C# driver.

Getting Started

To get started, fire up VisualStudio and create a new project. I'll be working with a console project for this tutorial. To install the driver, we'll go through NuGet and pull down the packages needed. There are three NuGet packages needed, and they are:

  1. MongoDB.Bson: The standalone BSON library that handles the conversion of POCOs to BSON types (which is the file format for MongoDB) and vice versa.
  2. [MongoDB.Driver.Core]((http://www.nuget.org/packages/mongodb.driver.core): This is a driver by itself and has the core components of the driver (like how to connect to a mongod instance, connection pooling, and the likes of it) for communicating from .Net to MongoDB and vice-versa, and has a dependency on MongoDB.Bson.
  3. MongoDB.Driver: Has a dependency on Driver.Core which in turn has a dependency on MongoDB.Bson. It has easier to use API over the core component driver and has async methods and supports querying with LINQ.

Run the following command to get all three packages installed at once:

Install-Package MongoDB.Driver

Accessing a database

To connect to a database we use the MongoClient class to access a mongodb instance and through it, select the database we want to use. This class has four constructors.

  • A parameterless contructor which by default, connects to an instance on port 27017:
var client = new MongoClient();
  • One that accepts a connection string:
var connectionString = "mongodb://localhost:27017";
var client = new MongoClient(connectionString);
  • Another that takes an instance of MongoUrl, and MongoUrl being similar to using the connectionstring param constructor. You can create an instance of this by using the default constructor:
var client = new MongoClient(new MongoUrl("mongodb://localhost:27017"));

...or using the static Create method from the class:

var client = new MongoClient(MongoUrl.Create("mongodb://localhost:27017"));
  • And also, a constructor that accepts a MongoClientSettings instance. There are many things you can set in here, like the credentials, connections lifetime and timeout, and many more. An example of doing this would be:
var settings1 = MongoClientSettings
        .FromUrl(MongoUrl.Create("mongodb://localhost:27017"));

var settings2 = new MongoClientSettings
          {
          Server = new MongoServerAddress("localhost", 27017),
          UseSsl = false
          };

var client1 = new MongoClient(settings1);
var client2 = new MongoClient(settings2);

Generally, you'd usually use the one constructor with the connectionString parameter, and we'll use this for this tutorial. I'll add an async method within the Main method because we'll be working with the async methods from the driver. If you're coding along, add the following code to your Program.cs file:

using MongoDB.Driver;
using System;
using System.Threading.Tasks;

namespace WorkingWithMongoDB
{
    class Program
    {
        static void Main(string[] args)
        {
            MainAsync().Wait();

            Console.ReadLine();
        }

        static async Task MainAsync()
        {
            var connectionString = "mongodb://localhost:27017";

            var client = new MongoClient(connectionString);
        }
    }
}

Now run the application and see that it successfully connects to the mongodb instance on that port; and from the console, you can see how many connections are open.

mongodb net

With MongoClient instance, there are a couple of things we can do like drop a database, get a database, or retrieve a the names of databases on the server. There is none for creating a database because once you pick a database and insert data into it, it automatically creates the database.

mongodb net

The one we're interested in is the GetDatabase method which will automatically create a database for us. So let's go ahead and fetch a database called school for which we'll work with:

IMongoDatabase db = client.GetDatabase("school");

The GetDatabase method returns an object which is a representation of a database, from which we can access different collections and manipulate the database. The MongoClient object is thread safe, so you can put it in a static field, make it a Singleton which you can get anytime through your DI container, or instantiate a new one using the same connection settings (which underneath will use the same connection pool); and through this object, you can pick any database you want to work with. I personally do have it as a Singleton registered to my chosen DI container.

With the database object, you can create, rename, retrieve, or get a list of collections from the database. Documents are stored in collections, so you can think of a collection as a table and documents as records in a table, if you're coming from the SQL world.

Create a collection

To create a collection, we use the CreateCollection or CreateCollectionAsync method of the IMongoDatabase object. This method takes in three parameters (of which the last two are optional):

  1. The name of the collection
  2. Create collection options
  3. A cancellation token:
void CreateCollection(
  string name,
  CreateCollectionOptions options = null,
  CancellationToken cancellationToken = null
)

Task CreateCollectionAsync(
  string name,
  CreateCollectionOptions options = null,
  CancellationToken cancellationToken = null
)

The CreateCollectionOptions specify settings for a collection, e.g. the maximum number of documents it should contain. Here's an example:

await db.CreateCollectionAsync("students", new CreateCollectionOptions
{
  AutoIndexId = false,
  MaxDocuments = 25,
        Capped = true
});

Most of the time, we just want to create a collection and leave the options at its default, by setting just the name of the collection.

await db.CreateCollectionAsync("students");

Another way a collection can also be created is using the GetCollection which accepts a name for the collection and an option collection settings as parameters. With this method, even though a collection of that name doesn't exist, it'll go ahead and create that collection once a document is being created. This would typically be the way you want to go, and would only use the create variant when you need to create a capped collection.

A capped collection is a fixed-sized collection that automatically overwrites its oldest entries when it reaches its maximum size. The GetCollection method is generic and you need to specify a document type when calling this method. The type represents the kind of object/document we want to work with. This could be strongly typed to any class we define, or use the BsonDocument type to represents a dynamic schema allowing us to work with any document shape in the collection.

Getting a collection

Having talked about creating a collection, it'll require an extra step to check if a collection exists, create it, and then add documents to a collection. The GetCollection automatically creates a collection if none exist and adds documents to that collection. Therefore, even though there's a CreateCollection, we'd typially want to go down this route. Just like the database, the collection is also thread safe and very cheap to create. To get a collection, we call the GetCollection method specifying the document type

static async Task MainAsync()
{
  ......
  IMongoCollection<BsonDocument> collection = db.GetCollection<BsonDocument>("students");
}

The BsonDocument is a type from the MongoDB.Bson package which represent a BSON Document and with this type, we can work with any shape of data from the database. This package contains all the basic BSON types and a few other things for working with BSON.

Within this package, we have classes that represent BSON types and how to map between .NET types and BsonValues. A few of those are:

  • The BsonDocument type as we've discussed
  • BsonElement which represent a BSON element
  • BsonValue which is an abstract base class used by various subclasses like the BsonString, BsonInt32, and many more.

The BsonDocument is a dictionary of string to BSON value, so we can initialize as we would any dictionary:

var document = new BsonDocument
{
  {"firstname", BsonValue.Create("Peter")},
  {"lastname", new BsonString("Mbanugo")},
  { "subjects", new BsonArray(new[] {"English", "Mathematics", "Physics"}) },
  { "class", "JSS 3" },
  { "age", int.MaxValue }
};

...or use the Add method which has a number of overloads:

var document = new BsonDocument();
document.Add("name", "Steven Johnson");
document.Add("age", 23);
document.Add("subjects", new BsonArray() {"English", "Mathematics", "Physics"});

...or use an indexer:

document["class"] = "JSS 3";

Creating/Inserting a document

Documents are stored within a collection and having looked at creating and getting a collection, we'll move on to inserting new documents in a collection. The mongo collection instance provides methods to insert a single document at a time or multiple documents at once.

To do this, we have to:

  • Get a hold of an object of type IMongocollection which represents the collection we want to work with:
var collection = db.GetCollection<BsonDocument>("students");
  • And then create the document we want:
var document = new BsonDocument
{
  {"firstname", BsonValue.Create("Peter")},
  {"lastname", new BsonString("Mbanugo")},
  { "subjects", new BsonArray(new[] {"English", "Mathematics", "Physics"}) },
  { "class", "JSS 3" },
  { "age", 45}
};
  • And finally insert the document:
await collection.InsertOneAsync(document);

To see this working, let's start a mongod instance from the command line and run the following lines of code while monitoring the events from the console:

class Program
{
  static void Main(string[] args)
  {
    MainAsync().Wait();

    Console.ReadLine();
  }

  static async Task MainAsync()
  {

    var client = new MongoClient();

    IMongoDatabase db = client.GetDatabase("school");
    var collection = db.GetCollection<BsonDocument>("students");

    var document = new BsonDocument
    {
      {"firstname", BsonValue.Create("Peter")},
      {"lastname", new BsonString("Mbanugo")},
      { "subjects", new BsonArray(new[] {"English", "Mathematics", "Physics"}) },
      { "class", "JSS 3" },
      { "age", 23 }
    };

    await collection.InsertOneAsync(document);
  }
}

... starting a mongod instance:
mongodb net

Run the application and watch the console:

mongodb net

You will notice that it called the insert command and succesfully inserted one document (ninserted: 1) . Also, there is a synchronous version of this method:

collection.InsertOne(document);

We can also insert multiple documents at the same time using the InsertMany or InsertManyAsync methods. Assuming we have three new students in the school, we can insert all at the same time using this method and they will be inserted in one batch (assuming you're using MongoDB 2.6 or higher). To see this in action, we move on to updating our code base and running the application:

class Program
{
  static void Main(string[] args)
  {
    MainAsync().Wait();

    Console.WriteLine("Press enter to exit");
    Console.ReadLine();
  }

  static async Task MainAsync()
  {

    var client = new MongoClient();

    IMongoDatabase db = client.GetDatabase("schoool");

    var collection = db.GetCollection<BsonDocument>("students");
    var newStudents = CreateNewStudents();

    await collection.InsertManyAsync(newStudents);
  }

  private static IEnumerable<BsonDocument> CreateNewStudents()
  {
    var student1 = new BsonDocument
    {
      {"firstname", "Ugo"},
      {"lastname", "Damian"},
      {"subjects", new BsonArray {"English", "Mathematics", "Physics", "Biology"}},
      {"class", "JSS 3"},
      {"age", 23}
    };

    var student2 = new BsonDocument
    {
      {"firstname", "Julie"},
      {"lastname", "Lerman"},
      {"subjects", new BsonArray {"English", "Mathematics", "Spanish"}},
      {"class", "JSS 3"},
      {"age", 23}
    };

    var student3 = new BsonDocument
    {
      {"firstname", "Julie"},
      {"lastname", "Lerman"},
      {"subjects", new BsonArray {"English", "Mathematics", "Physics", "Chemistry"}},
      {"class", "JSS 1"},
      {"age", 25}
    };

    var newStudents = new List<BsonDocument>();
    newStudents.Add(student1);
    newStudents.Add(student2);
    newStudents.Add(student3);

    return newStudents;
  }
}

mongodb net

From the console, you can see that it issued an insert command for three documents and successfully inserted all of them. Aside from working with the BsonDocument, we usually know beforehand what kind of data we want to work with and we can create custom .Net classes for them. Following our example of working with the students collection, let's create a Student class and insert new students represented using this class:

internal class Student
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string Class { get; set; }
  public int Age { get; set; }
  public IEnumerable<string> Subjects { get; set; }
}
class Program
{
  static void Main(string[] args)
  {
    MainAsync().Wait();

    Console.WriteLine("Press enter to exit");
    Console.ReadLine();
  }

  static async Task MainAsync()
  {

    var client = new MongoClient();

    IMongoDatabase db = client.GetDatabase("schoool");

    var collection = db.GetCollection<Student>("students");
    var newStudents = CreateNewStudents();

    await collection.InsertManyAsync(newStudents);
  }

  private static IEnumerable<Student> CreateNewStudents()
  {
    var student1 = new Student
    {
      FirstName= "Gregor",
      LastName= "Felix",
      Subjects = new List<string>() {"English", "Mathematics", "Physics", "Biology"},
      Class = "JSS 3",
      Age = 23
    };

    var student2 = new Student
    {
      FirstName = "Machiko",
      LastName = "Elkberg",
      Subjects = new List<string> {"English", "Mathematics", "Spanish"},
      Class = "JSS 3",
      Age =  23
    };

    var student3 = new Student
    {
      FirstName = "Julie",
      LastName = "Sandal",
      Subjects = new List<string> {"English", "Mathematics", "Physics", "Chemistry"},
      Class = "JSS 1",
      Age = 25
    };

    var newStudents = new List<Student> {student1, student2, student3};

    return newStudents;
  }
}

With the code above we can change the document type for the collection to the new class, and call the insert method. To see that this works, let's run the application and monitor what happens from the console.

mongodb net

Wrapping up

And from that, we can see that it actually does insert the documents. Having looked at all this, I certainly hope that some basics of the .Net driver is clear and we know how to insert document(s). In the next part, we'll walk through retrieving documents and the various ways to build queries for that purpose.

Discover and read more posts from Peter Mbanugo
get started
post commentsBe the first to share your opinion
Liam Murphy
4 years ago

Nice article; I’d love to hear peoples experiences with scaling Mongo deployments. During some initial load testing I’ve found that using the InsertOneAsync method became fairly unreliable once I ramped up 50 concurrent operations…I started to receive MongoWaitQueueFullException. Replacing this with the synchronous InsertOne version fixed the problem to the point that I could not get it to fail no matter how hard I tried…however, I am guessing this have knock-on effects to the server hosting the components that connect to mongo. Any thoughts\comments on this scenario?

Serhii Konovalov
5 years ago

Thank you! Excellent work!

Mohamed Yasin
5 years ago

Hi , i am new to mongodb , currently i am struggling to connect mongodb (C#) with credential and disconnect database, can you please help me to solve this?

Peter Mbanugo
5 years ago

what errors are you getting?

Mohamed Yasin
5 years ago

Hi Peter,
now i’m trying to disconnect the database connection using below code

MongoDB.Driver.MongoDatabase _database = (MongoDB.Driver.MongoDatabase)meta.MongoConnection;

                _database.Server.Disconnect();

After executing the above code i didn’t see any errors, but still the state shows connected.

Show more replies