Driver Tutorial

Introduction

This tutorial introduces the officially supported C# Driver for
MongoDB. The C# Driver consists of two libraries: the BSON Library and
the C# Driver. The BSON Library can be used independently of the C#
Driver if desired. The C# Driver requires the BSON Library.

You may also be interested in the C# Driver Serialization
Tutorial </tutorial/serialize-documents-with-the-csharp-driver>. It is
a separate tutorial because it covers quite a lot of material.

Downloading

The C# Driver is available in source and binary form. While the BSON
Library can be used independently of the C# Driver they are both stored
in the same repository.

The simplest way to get started is by using the nuget package. The
package page will
provide details on using nuget.

You must set the global setting for core.autocrlf to true before
cloning the repository. After you clone the repository, we recommend you
set the local setting for core.autocrlf to true (as shown above) so
that future changes to the global setting for core.autocrlf do not
affect this repository. If you then want to change your global setting
for core.autocrlf to false run:

git config --global core.autocrlf false

The typical symptom of problems with the setting for core.autocrlf is
git reporting that an entire file has been modified (because of
differences in the line endings). It is rather tedious to change the
setting of core.autocrlf for a repository after it has been created,
so it is important to get it right from the start.

Building

We are currently building the C# Driver with Visual Studio 2012. The
name of the solution file is CSharpDriver.sln.

Running Unit Tests

The unit tests depend on NUnit 2.6, which is included in the Tools
folder of the repository. You can build the C# Driver without
installing NUnit, but you must have a test runner capable of running
NUnit tests in order to run the tests.

There are three projects containing unit tests:

BsonUnitTests

DriverUnitTests

DriverUnitTestsVB

The BsonUnitTests do not connect to a MongoDB server. The
DriverUnitTests and DriverUnitTestsVB connect to an instance of
MongoDB running on the default port (27017) on localhost.

If you are running Visual Studio 2012, you can use the NUnit Test
Adapter extension to run the unit tests. This is by far the easiest
solution.

note

The NUnit Test Adapter for Visual Studio 2012 is an extension that
must be installed through the Visual Studio Extension Manager.

An alternative is to use the NUnit Test Runner. An easy way to use the
NUnit Test Runner is to set one of the unit test projects as the startup
project and configure the project settings as follows (using
BsonUnitTests as an example):

Set working directory to: the directory where
BsonUnitTest.csproj is located.

Repeat the above steps for the Release configuration (using
/config:Release instead) if you also want to run unit tests for
Release builds.

To run the DriverUnitTests and DriverUnitTestsVB perform the same
steps (modified as necessary).

Installing

If you want to install the C# Driver on your machine, you can use the
setup program (see above for download instructions). The setup program
is very simple and just copies the DLLs to your specified installation
directory.

If you downloaded the binaries zip file simply extract the files and
place them wherever you want them to be.

note

If you download the .zip file, Windows might require you to
“Unblock” the help file. If Windows asks “Do you want to open this
file?” when you double click on the CSharpDriverDocs.chm file, clear
the check box next to “Always ask before opening this file” before
pressing the Open button. Alternatively, you can right click on the
CSharpDriverDocs.chm file and select Properties, and then press the
Unblock button at the bottom of the General tab. If the Unblock
button is not present then the help file does not need to be
unblocked.

References and Namespaces

To use the C# Driver you must add references to the following DLLs:

MongoDB.Bson.dll

MongoDB.Driver.dll

note

If you used nuget to pull down the assemblies, these references likely
already exist.

As a minimum add the following using statements to your source files:

using MongoDB.Bson;
using MongoDB.Driver;

Additionally you will frequently add some of the following using
statements:

using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;
using MongoDB.Driver.Linq;

In some cases you might add some of the following using statements if
you are using some of the optional parts of the C# 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.Wrappers;

The BSON Library

The C# Driver is built on top of the BSON Library, which handles all
the details of the BSON specification, including: I/O, serialization,
and an in-memory object model of BSON documents.

The important classes of the BSON object model are: BsonType,
BsonValue, BsonElement, BsonDocument and BsonArray.

BsonType

This enumeration is used to specify the type of a BSON value. It is
defined as:

BsonValue and Subclasses

BsonValue is an abstract class that represents a typed BSON value.
There is a concrete subclass of BsonValue for each of the values
defined by the BsonType enum. There are several ways to obtain an
instance of BsonValue:

Use a public constructor (if available) of a subclass of BsonValue

Use a static Create method of BsonValue

Use a static Create method of a subclass of BsonValue

Use a static property of a subclass of BsonValue

Use an implicit conversion to BsonValue

The advantage of using the static Create methods is that they can
return a pre-created instance for frequently used values. They can also
return null (which a constructor cannot) which is useful for handling
optional elements when creating BsonDocuments using functional
construction. The static properties refer to pre-created instances of
frequently used values. Implicit conversions allow you to use primitive
.NET values wherever a BsonValue is expected, and the .NET value will
automatically be converted to a BsonValue.

BsonType Property

BsonValue has a property called BsonType that you can use to query
the actual type of a BsonValue. The following example shows several
ways to determine the type of a BsonValue:

BsonValue value;
if (value.BsonType == BsonType.Int32) {
// we know value is an instance of BsonInt32
}
if (value is BsonInt32) {
// another way to tell that value is a BsonInt32
}
if (value.IsInt32) {
// the easiest way to tell that value is a BsonInt32
}

As[Type] Properties

BsonValue has a number of properties that cast a BsonValue to one of
its subclasses or a primitive .NET type. It is important to note that
these all are casts, not conversions. They will throw an
InvalidCastException if the BsonValue is not of the corresponding
type. See also the To[Type] methods
<totype-conversion-methods> which do conversions, and the
Is[Type] properties <istype-properties> which you can use to query the
type of a BsonValue before attempting to use one of the As[Type]
properties.

To[Type] Conversion Methods

Unlike the As[Type] methods, the To[Type] methods perform some
limited conversion between convertible types, like int and double.

The ToBoolean method never fails. It uses JavaScript’s definition of
truthiness: false, 0, 0.0, NaN, BsonNull, BsonUndefined and
"" are false, and everything else is true (include the string
"false").

The ToBoolean method is particularly useful when the documents you are
processing might have inconsistent ways of recording true/false
values:

if (employee["ismanager"].ToBoolean()) {
// we know the employee is a manager
// works with many ways of recording boolean values
}

The ToDouble, ToInt32, and ToInt64 methods never fail when
converting between numeric types, though the value might be truncated if
it doesn’t fit in the target type. A string can be converted to a
numeric type, but an exception will be thrown if the string cannot be
parsed as a value of the target type.

Static Create Methods

Because BsonValue is an abstract class you cannot create instances of
BsonValue (only instances of concrete subclasses). BsonValue has a
static Create method that takes an argument of type object and
determines at runtime the actual type of BsonValue to create.
Subclasses of BsonValue also have static Create methods tailored to
their own needs.

Implicit Conversions

Implicit conversions are defined from the following .NET types to
BsonValue:

bool

byte[]

DateTime

double

Enum

Guid

int

long

ObjectId

Regex

string

These eliminate the need for almost all calls to BsonValue
constructors or Create methods. For example:

BsonValue b = true; // b is an instance of BsonBoolean
BsonValue d = 3.14159; // d is an instance of BsonDouble
BsonValue i = 1; // i is an instance of BsonInt32
BsonValue s = "Hello"; // s is an instance of BsonString

BsonMaxKey, BsonMinKey, BsonNull and BsonUndefined

These classes are singletons, so only a single instance of each class
exists. You refer to these instances using the static Value property
of each class:

Note that C# null and BsonNull.Value are two different things. The
latter is an actual C# object that represents a BSON null value (it’s
a subtle difference, but plays an important role in functional
construction).

ObjectId and BsonObjectId

ObjectId is a struct that holds the raw value of a BSON ObjectId.
BsonObjectId is a subclass of BsonValue whose Value property is of
type ObjectId.

The first example behaves differently in C# than in JavaScript. In
C# it creates an ObjectId of all zeroes, but in JavaScript it
generates a new unique Id. This difference can’t be avoided because
in C# the default constructor of a value type always initializes the
value to all zeros.

BsonElement

A BsonElement is a name/value pair, where the value is a BsonValue.
It is used as the building block of BsonDocument, which consists of
zero or more elements. You will rarely create BsonElements directly,
as they are usually created indirectly as needed. For example:

The first two are the ones you are most likely to use. The first creates
an empty document, and the second creates a document with one element
(in both cases you can of course add more elements).

All the constructors (except the one with allowDuplicateNames) simply
call the Add method that takes the same parameters, so refer to the
corresponding Add method for details about how the new document is
initially populated.

A BsonDocument normally does not allow duplicate names, but if you
must allow duplicate names call the constructor with the
allowDuplicateNames parameter and pass in true. It is not
recommended that you allow duplicate names, and this option exists only
to allow handling existing BSON documents that might have duplicate
names. MongoDB makes no particular guarantees about whether it supports
documents with duplicate names, so be cautious about sending any such
documents you construct to the server.

Create a New Document and Call Add and Set Methods

This is a traditional step by step method to create and populate a
document using multiple C# statements. For example:

This creates a top level document with two elements (name and
address). The value of address is a nested BSON document.

Add Methods

BsonDocument has the following overloaded Add methods:

Add(BsonElement element)

Add(Dictionary<string, object> dictionary)

Add(Dictionary<string, object> dictionary, IEnumerable<string> keys)

Add(IDictionary dictionary)

Add(IDictionary dictionary, IEnumerable<string> keys)

Add(IDictionary<string, object> dictionary)

Add(IDictionary<string, object> dictionary, IEnumerable<string> keys)

Add(IEnumerable<BsonElement> elements)

Add(string name, BsonValue value)

Add(string name, BsonValue value, bool condition)

It is important to note that sometimes the Add methods do NOT add a
new element. If the value supplied is null (or the condition supplied
in the last overload is false) then the element isn’t added. This
makes it really easy to handle optional elements without having to write
any if statements or conditional expressions.

The IDictionary overloads initialize a BsonDocument from a
dictionary. Each key in the dictionary becomes the name of a new
element, and each value is mapped to a matching BsonValue and becomes
the value of the new element. The overload with the keys parameter lets
you select which dictionary entries to load (you might also use the keys
parameter to control the order in which the elements are loaded from the
dictionary).

Accessing BsonDocument Elements

The recommended way to access BsonDocument elements is to use one of
the following indexers:

BsonValue this[int index]

BsonValue this[string name]

BsonValue this[string name, BsonValue defaultValue]

Note that the return value of the indexers is BsonValue, not
BsonElement. This actually makes BsonDocuments much easier to work
with (if you ever need to get the actual BsonElements use
GetElement).

We’ve already seen samples of accessing BsonDocument elements. Here
are some more:

BsonArray

This class is used to represent BSON arrays. While arrays happen to be
represented externally as BSON documents (with a special naming
convention for the elements), the BsonArray class is unrelated to the
BsonDocument class because they are used very differently.

Constructors

BsonArray has the following constructors:

BsonArray()

BsonArray(IEnumerable<bool> values)

BsonArray(IEnumerable<BsonValue> values)

BsonArray(IEnumerable<DateTime> values)

BsonArray(IEnumerable<double> values)

BsonArray(IEnumerable<int> values)

BsonArray(IEnumerable<long> values)

BsonArray(IEnumerable<ObjectId> values)

BsonArray(IEnumerable<string> values)

BsonArray(IEnumerable values)

All the constructors with a parameter call the matching Add method.
The multiple overloads are needed because C# does not provide automatic
conversions from IEnumerable<T> to IEnumerable<object>.

Add and AddRange Methods

BsonArray has the following Add methods:

BsonArray Add(BsonValue value)

BsonArray AddRange(IEnumerable<bool> values)

BsonArray AddRange(IEnumerable<BsonValue> values)

BsonArray AddRange(IEnumerable<DateTime> values)

BsonArray AddRange(IEnumerable<double> values)

BsonArray AddRange(IEnumerable<int> values)

BsonArray AddRange(IEnumerable<long> values)

BsonArray AddRange(IEnumerable<ObjectId> values)

BsonArray AddRange(IEnumerable<string> values)

BsonArray AddRange(IEnumerable values)

Note that the Add method takes a single parameter. To create and
initialize a BsonArray with multiple values use any of the following
approaches:

LazyBsonDocument and LazyBsonArray

The lazy classes are special in that they defer the deserialiation of
BSON until it is needed. This is useful for when you only need a field
or two out of a complex document because it will not incur the cost of
deserializing the entire document or array, but just the pieces that are
necessary. This deserialization occurs a level at a time. For example,
in the following document, asking for field FirstName will deserialize
LastName and BirthDate as well, but it will leave Addresses in its
serialized form until they are accessed.

LazyBsonDocument and LazyBsonArray implement IDisposable. It is very
important that these classes be disposed of to ensure high performance
and lower memory utilization.

RawBsonDocument and RawBsonArray

The raw classes are special in that they defer the deserialiation of
BSON until it is needed. This is useful for when you only need a field
or two out of a document and will not be accessing them repeatedly. The
Raw documents are best utilized when shuffling data from one database or
collection to another one in MongoDB or to another, external storage
location.

note

The behavior of the RawXXX classes differ from that of the LazyXXX
classes in that repeated access to the same field in the LazyXXX
version will not incur repeated deserialization overhead whereas the
RawXXX version will deserialize the same field without caching on
repeated requests.

It can be used as follows:

var db = server.GetDatabase("foo");
var col = db.GetCollection<RawBsonDocument>("bar");
foreach (var doc in col.Find(Query.GT("age", 15)))
{
using (doc)
{
// this access incurs the cost of deserializing
// the FirstName element.
var firstName = doc["FirstName"];
// even though this was deserialized just above,
// it will need to get re-deserialized because
// we do not store the results of deserialization.
var firstNameAgain = doc["FirstName"];
Console.WriteLine("{0} {1}", doc["FirstName"], doc[])
}
}

note

The Raw classes are readonly and will throw exceptions if attempts are
made to update them.

warning

RawBsonDocument and RawBsonArray implement IDisposable. It is very
important that these classes be disposed of to ensure high performance
and lower memory utilization.

The C# Driver

Up until now we have been focusing on the BSON Library. The remainder of
this tutorial focuses on the C# Driver.

Thread Safety

Only a few of the C# Driver classes are thread safe. Among them:
MongoClient, MongoServer, MongoDatabase, MongoCollection and
MongoGridFS. Common classes you will use a lot that are not thread
safe include MongoCursor and all the classes from the BSON Library
(except BsonSymbolTable which is thread safe). A class is not thread
safe unless specifically documented as being thread safe.

All static properties and methods of all classes are thread safe.

MongoClient Class

This class serves as the root object for working with a MongoDB server.
The connections to the server are handled automatically behind the
scenes (a connection pool is used to increase efficiency).

When you are connecting to a replica set you will still use only one
instance of MongoClient, which represents the replica set as a whole.
The driver automatically finds all the members of the replica set and
identifies the current primary.

Instances of this class are thread safe.

By default and unless set otherwise, all operations requiring a
WriteConcern use w=1. In other words, by default, all write
operations will block until the server has acknowledged the write.

Connection Strings

The easiest way to connect to a MongoDB server is to use a connection
string. The standard connection string format is:

mongodb://[username:password@]hostname[:port][/[database][?options]]

The username and password should only be present if you are using
authentication on the MongoDB server. The database segment indicates
which database the username is designated. When not specified, the
default database is admin.

note

If you are using the database segment as the initial database to
use, but the username and password specified are defined in a
different database, you can use the authSource option to specify the
database in which the credential is defined. For example,
mongodb://user:pass@hostname/db1?authSource=userDb would authenticate
the credential against the userDb database instead of db1.

warning

Versions prior to 1.8 of the driver allowed the specification of an
admin credential by appending (admin) to the username. This is not
recognized as of version 1.8. Consult the official connection string
documentation
for more information.

The port number is optional and defaults to 27017.

To connect to multiple servers, specify the seed list by providing
multiple hostnames (and port numbers if required) separated by commas.
For example:

mongodb://server1,server2:27017,server2:27018

This connection string specifies a seed list consisting of three servers
(two of which are on the same machine but on different port numbers).
Because specifying multiple servers is ambiguous as to whether or not it
is a replica set or multiple mongos (in a sharded setup), the driver
will go through a discovery phase of connecting to the servers to
determine their type. This has a little overhead at connection time and
can be avoided by specifying a connection mode in the connection string:

warning

It is required that each MongoDB server have a name that is DNS
resolvable by the client machine. Each MongoDB server reports its
hostname back through the isMaster command and the driver uses this
name to talk with the server. This issue can occur when the seed list
contains an IP address and the MongoDB server reports back a hostname
that the client machine is unable to resolve.

mongodb://server1,server2:27017,server2:27018/?connect=replicaset

The available connection modes are automatic (the default), direct,
replica set, and shardrouter. The rules for connection mode are as
follows:

If a connect mode is specified other than automatic, it is used.

If the option replicaset is specified on the connection string using
literal ?connect=replicaset then replicaset mode is used. Don’t
use replica set name.

If there is only one server listed on the connection string, then
direct mode is used.

Otherwise, discovery occurs and the first server to respond
determines the connection mode.

note

If you have multiple servers listed, and one is part of a replica set
and another is not, then the connection mode is non-deterministic. Be
sure that you are not mixing server types on the connection string.

Should the connection mode resolve to a replica set, the driver will
find the primary server even if it is not in the seed list, as long as
at least one of the servers in the seed list responds (the response will
contain the full replica set and the name of the current primary). In
addition, other secondaries will also be discovered and added (or
removed) into the mix automatically, even after initial connection. This
will enable you to add and remove servers from the replica set and the
driver will handle the changes automatically.

As alluded to above, the options part of the connection string is used
to set various connection options. Suppose you wanted to connect
directly to a member of a replica set regardless of whether it was the
current primary or not (perhaps to monitor its status or to issue read
only queries against it). You could use:

SSL Support

Support for SSL is baked into the driver. You can configure this via the
connection string be adding an ssl=true option to the options.

mongodb://server2/?ssl=true

By default, the server certificate will get validated against the local
trusted certificate store. This sometimes causes issues in test
environments where test servers don’t have signed certs. To alleviate
this issue, you can also add an sslverifycertificate=false as another
connection string option to ignore any certificate errors.

In addition to the above connection string settings, there are a number
of settings that can be utilized through code. The SslSettings class
is the container of these settings.

Authentication

The .NET driver supports both MongoDB’s authentication simple protocol
as well as the more complex and robust Kerberos protocol. This enables
the driver to function with single-sign-on functionality against a
Kerberose Key Distribution Center. One such KDC is Active Directory. See
below for more details:

/tutorial/authenticate-with-csharp-driver

warning

Version 2.4 of the server supports Delegated
Authentication.
Due to this change, the 1.8 release of the driver has some backwards
breaking changes in order to support this feature. Most importantly,
all the credentials supplied in a MongoClientSettings instance will be
authenticated when a new connection is opened, regardless of the
database you are currently using.

GetServer Method

You can navigate from an instance of a MongoClient to an instance of
MongoServer by using the GetServer method.

MongoServer Class

The MongoServer class is used to provide more control over the driver.
It contains advanced ways of getting a database and pushing a sequence
of operations through a single socket in order to guarantee consistency.

GetDatabase Method

You can navigate from an instance of MongoServer to an instance of
MongoDatabase (see next section) using one of the following
GetDatabase methods or indexers:

Most of the database settings are inherited from the server object, and
the provided overloads of GetDatabase let you override a few of the
most commonly used settings. To override other settings, call
CreateDatabaseSettings and change any settings you want before calling
GetDatabase, like this:

GetDatabase maintains a table of MongoDatabase instances it has
returned before, so if you call GetDatabase again with the same
parameters you get the same instance back again.

RequestStart/RequestDone Methods

Sometimes a series of operations needs to be performed on the same
connection in order to guarantee correct results. This is rarely the
case, and most of the time there is no need to call
RequestStart/RequestDone. An example of when this might be necessary
is when a series of Inserts are called in rapid succession with a
WriteConcern of w=0, and you want to query that data is in a
consistent manner immediately thereafter (with a WriteConcern of
w=0, the writes can queue up at the server and might not be
immediately visible to other connections). Using RequestStart you can
force a query to be on the same connection as the writes, so the query
won’t execute until the server has caught up with the writes.

A thread can temporarily reserve a connection from the connection pool
by using RequestStart and RequestDone. For example:

using(server.RequestStart(database)) {
// a series of operations that must be performed on the same connection
}

The database parameter simply indicates some database which you intend
to use during this request. This allows the server to pick a connection
that is already authenticated for that database (if you are not using
authentication then this optimization won’t matter to you). You are free
to use any other databases as well during the request.

RequestStart increments a counter (for this thread) which is
decremented upon completion. The connection that was reserved is not
actually returned to the connection pool until the count reaches zero
again. This means that calls to RequestStart can be nested and the
right thing will happen.

note

RequestStart returns an IDisposable. If you do not use
RequestStart with a using block, it is imperative that
RequestDone be called in order to release the connection.

Other Properties and Methods

For a reference of other properties and method, see the api
documentation.

MongoDatabase Class

This class represents a database on a MongoDB server. Normally there
will be only one instance of this class per database, unless you are
using different settings to access the same database, in which case
there will be one instance for each set of settings.

Instances of this class are thread safe.

GetCollection Method

This method returns an object representing a collection in a database.
When we request a collection object, we also specify the default
document type for the collection. For example:

A collection is not restricted to containing only one kind of document.
The default document type simply makes it more convenient to work with
that kind of document, but you can always specify a different kind of
document when required.

Most of the collection settings are inherited from the database object,
and the provided overloads of GetCollection let you override a few of
the most commonly used settings. To override other settings, call
CreateCollectionSettings and change any settings you want before
calling GetCollection , like this:

GetCollection maintains a table of instances it has returned before,
so if you call GetCollection again with the same parameters you get
the same instance back again.

Other Properties and Methods

For a reference of other properties and method, see the api
documentation.

MongoCollection<TDefaultDocument> Class

This class represents a collection in a MongoDB database. The
<TDefaultDocument> type parameter specifies the type of the default
document for this collection.

Instances of this class are thread safe.

Insert<TDocument> Method

To insert a document in the collection create an object representing the
document and call Insert. The object can be an instance of
BsonDocument or of any class that can be successfully serialized as a
BSON document. For example:

When you are inserting multiple documents InsertBatch can be much more
efficient than Insert.

FindOne and FindOneAs Methods

To retrieve documents from a collection use one of the various Find
methods. FindOne is the simplest. It returns the first document it
finds (when there are many documents in a collection you can’t be sure
which one it will be). For example:

MongoCollection<Book> books;
Book book = books.FindOne();

If you want to read a document that is not of the <TDefaultDocument>
type use the FindOneAs method, which allows you to override the type
of the returned document. For example:

In this case the default document type of the collection is Book, but
we are overriding that and specifying that the result be returned as an
instance of BsonDocument.

Find and FindAs Methods

The Find and FindAs methods take a query that tells the server which
documents to return. The query parameter is of type IMongoQuery.
IMongoQuery is a marker interface that identifies classes that can be
used as queries. The most common ways to construct a query are to either
use the Query builder class or to create a QueryDocument yourself (a
QueryDocument is a subclass of BsonDocument that also implements
IMongoQuery and can therefore be used as a query object).

Save<TDocument> Method

The Save method is a combination of Insert and Update. If the Id
member of the document has a value, then it is assumed to be an existing
document and Save calls Update on the document (setting the Upsert
flag just in case it actually is a new document after all). Otherwise it
is assumed to be a new document and Save calls Insert after first
assigning a newly generated unique value to the Id member.

FindAndModify Method

Use FindAndModify when you want to find a matching document and update
it in one atomic operation. FindAndModify always updates a single
document, and you can combine a query that matches multiple documents
with a sort criteria that will determine exactly which matching document
is updated. In addition, FindAndModify will return the matching
document (either as it was before the update or after) and if you wish
you can specify which fields of the matching document to return.

Using the example documented here, findAndModify
Command,
the call to FindAndModify would be written in C# as:

MapReduce Method

Map/Reduce is a way of aggregating data from a collection. Every
document in a collection (or some subset if an optional query is
provided) is sent to the map function, which calls emit to produce
intermediate values. The intermediate values are then sent to the
reduce function to be aggregated.

This example is taken from page 87 of MongoDB: The Definitive Guide,
by Kristina Chodorow and Michael Dirolf. It counts how many times each
key is found in a collection.

Other Properties and Methods

For a reference of other properties and method, see the api
documentation.

MongoCursor<TDocument> Class

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.

Instances of MongoCursor are not thread safe, at least not until they
are frozen (see below). Once they are frozen they are thread safe
because they are read-only (in particular, GetEnumerator is thread
safe so the same cursor could be used by multiple threads).

Enumerating a cursor

The most convenient way to consume the results of a query is to use the
C# foreach statement. For example:

In the above example, the query is actually sent to the server twice
(once when FirstOrDefault is called and again when LastOrDefault
is called).

It is important that a cursor cleanly release any resources it holds.
The key to guaranteeing this is to make sure the Dispose method of the
enumerator is called. The foreach statement and the LINQ extension
methods all guarantee that Dispose will be called. Only if you
enumerate the cursor manually are you responsible for calling Dispose.

Modifying a Cursor Before Enumerating It

A cursor has several properties that can be modified before it is
enumerated to control the results returned. There are two ways to modify
a cursor:

Modify the properties directly.

Use the fluent interface to set the properties.

For example, if we want to skip the first 100 results and limit the
results to the next 10, we could write:

The fluent interface works well when you are setting only a few values.
When setting more than a few you might prefer to use the properties
approach.

Once you begin enumerating a cursor it becomes “frozen” and you can no
longer change any of its properties. So you must set all the properties
before you start enumerating it.

Modifiable Properties of a Cursor

The following properties of a cursor are modifiable:

BatchSize (SetBatchSize)

Fields (SetFields)

Flags (SetFlags)

Limit (SetLimit)

Options (SetOption and SetOptions)

SerializationOptions (SetSerializationOptions)

Skip (SetSkip)

SlaveOk (SetSlaveOk)

The names in parenthesis are the corresponding fluent interface method
names.

The fluent interface also supports additional options that aren’t used
very frequently and are not exposed as properties:

SetHint

SetMax

SetMaxScan

SetMaxTime

SetMin

SetShowDiskLoc

SetSnapshot

SetSortOrder

Other Methods

MongoCursor has a few methods used for some special purpose
operations:

Clone

Count

Explain

Size

WriteConcern Class

There are various levels of WriteConcern, and this class is used to
represent those levels. WriteConcern applies only to operations that
don’t already return a value (so it doesn’t apply to queries or
commands). It applies to the following MongoCollection methods:
Insert, Remove, Save and Update.

The gist of WriteConcern is that after an Insert, Remove, Save
or Update message is sent to the server it is followed by a
GetLastError command so the driver can verify that the operation
succeeded. In addition, when using replica sets it is possible to verify
that the information has been replicated to some minimum number of
secondary servers.

MaxTime

MongoDB 2.6 introduced the ability to timeout individual queries:

coll.FindAll().SetMaxTime(TimeSpan.FromSeconds(1));

In the example above the maxTimeMS is set to one second and the query
will be aborted after the full second is up.

Bulk operations

Under the covers MongoDB is moving away from the combination of a write
operation followed by get last error (GLE) and towards a write commands
API. These new commands allow for the execution of bulk
insert/update/remove operations. There are two types of bulk operations:

Ordered bulk operations.

: Executes all the operations in order and error out on the first
write error.

Unordered bulk operations.

: Executes all the operations in parallel and aggregates all the
errors. Unordered bulk operations do not guarantee order of
execution.

Let’s look at two simple examples using ordered and unordered
operations:

For servers older than 2.6 the API will down-convert the operations.
To support the correct semantics for BulkWriteResult and
BulkWriteException, the operations have to be done one at a time. It’s
not possible to down convert 100% so there might be slight edge cases
where it cannot correctly report the right numbers.