C# Driver version v1.2This tutorial is for v1.2 of the C# Driver. IntroductionThis tutorial introduces the 10gen 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. It is a separate tutorial because it covers quite a lot of material. DownloadingThe 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 source may be downloaded from github.com. We use msysgit as our Windows git client. It can be downloaded from: http://code.google.com/p/msysgit/. To clone the repository run the following commands from a git bash shell: $ cd <parentdirectory> $ git config --global core.autocrlf true $ git clone git://github.com/mongodb/mongo-csharp-driver.git $ cd mongo-csharp-driver $ git config core.autocrlf true 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. You can download a zip file of the source files (without cloning the repository) by clicking on the Downloads button at: http://github.com/mongodb/mongo-csharp-driver You can download binaries (in both .msi and .zip formats) from: http://github.com/mongodb/mongo-csharp-driver/downloads BuildingWe are currently building the C# Driver with Visual Studio 2008 and Visual Studio 2010. There are two solution files, one for each version of Visual Studio. The names of the solution files are CSharpDriver-2008.sln and CSharpDriver-2010.sln. The project files are shared by both solutions. DependenciesThe unit tests depend on NUnit 2.5.9, which is included in the dependencies folder of the repository. You can build the C# Driver without installing NUnit, but you must install NUnit before running the unit tests (unless you use a different test runner). Running unit testsThere are three projects containing unit tests: 1. BsonUnitTests The first two do not connect to a MongoDB server. DriverOnlineUnitTests connects to an instance of MongoDB running on the default port on localhost. An easy way to run the unit tests 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):
The exact location of the nunit.exe program might vary slightly on your machine. To run the DriverUnitTests or DriverOnlineUnitTests perform the same steps (modified as necessary). InstallingIf 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:
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 namespacesTo use the C# Driver you must add references to the following DLLs:
You also will likely want to add the following using statements to your source files: using MongoDB.Bson; using MongoDB.Driver; You might need to 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.Builders; using MongoDB.Driver.GridFS; using MongoDB.Driver.Wrappers; The BSON LibraryThe 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. BsonTypeThis enumeration is used to specify the type of a BSON value. It is defined as: public enum BsonType { Double = 0x01, String = 0x02, Document = 0x03, Array = 0x04, Binary = 0x05, Undefined = 0x06, ObjectId = 0x07, Boolean = 0x08, DateTime = 0x09, Null = 0x0a, RegularExpression = 0x0b, JavaScript = 0x0d, Symbol = 0x0e, JavaScriptWithScope = 0x0f, Int32 = 0x10, Timestamp = 0x11, Int64 = 0x12, MinKey = 0xff, MaxKey = 0x7f } BsonValue and subclassesBsonValue 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:
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. BsonValue has the following subclasses:
BsonType propertyBsonValue 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] PropertiesBsonValue 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 which do conversions, and the Is[Type] properties which you can use to query the type of a BsonValue before attempting to use one of the As[Type] properties. Sample code using these properties: BsonDocument document; string name = document["name"].AsString; int age = document["age"].AsInt32; BsonDocument address = document["address"].AsBsonDocument; string zip = address["zip"].AsString; Is[Type] PropertiesBsonValue has the following boolean properties you can use to test what kind of BsonValue it is:
Sample code: BsonDocument document; int age = -1; if (document.Contains["age"] && document["age"].IsInt32) { age = document["age"].AsInt32; } To[Type] conversion methodsThe following methods are available to do limited conversions between BsonValue types:
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 methodsBecause 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 conversionsImplicit conversions are defined from the following .NET types to BsonValue:
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 BsonUndefinedThese 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: document["status"] = BsonNull.Value; document["priority"] = BsonMaxKey.Value; 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 BsonObjectIdObjectId 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. Here are some common ways of creating ObjectId values: var id1 = new ObjectId(); // same as ObjectId.Empty var id2 = ObjectId.Empty; // all zeroes var id3 = ObjectId.GenerateNewId(); // generates new unique Id var id4 = ObjectId.Parse("4dad901291c2949e7a5b6aa8"); // parses a 24 hex digit string Note that 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. BsonElementA 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: document.Add(new BsonElement("age", 21)); // OK, but next line is shorter document.Add("age", 21); // creates BsonElement automatically BsonDocumentA BsonDocument is a collection of name/value pairs (represented by BsonElements). It is an in-memory object model of a BSON document. There are three ways to create and populate a BsonDocument:
BsonDocument constructorBsonDocument has the following constructors:
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 coresponding 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 methodsThis is a traditional step by step method to create and populate a document using multiple C# statements. For example: BsonDocument book = new BsonDocument(); book .Add("author", "Ernest Hemingway"); book .Add("title", "For Whom the Bell Tolls"); Create a new document and use the fluent interface Add and Set methodsThis is similar to the previous approach but the fluent interface allows you to chain the various calls to Add so that they are all a single C# statement. For example: BsonDocument book = new BsonDocument() .Add("author", "Ernest Hemingway") .Add("title", "For Whom the Bell Tolls"); Create a new document and use C#'s collection initializer syntax (recommended)This is the recommended way to create and initialize a BsonDocument in one statement. It uses C#'s collection initializer syntax: BsonDocument book = new BsonDocument { { "author", "Ernest Hemingway" }, { "title", "For Whom the Bell Tolls" } }; The compiler translates this into calls to the matching Add method: BsonDocument book = new BsonDocument(); book.Add("author", "Ernest Hemingway"); book.Add("title", "For Whom the Bell Tolls"); A common mistake is to forget the inner set of braces. This will result in a compilation error. For example: BsonDocument bad = new BsonDocument { "author", "Ernest Hemingway" }; is translated by the compiler to: BsonDocument bad = new BsonDocument(); bad.Add("author"); bad.Add("Ernest Hemingway"); which results in a compilation error because there is no Add method that takes a single string argument. Creating nested BSON documentsNested BSON documents are created by setting the value of an element to a BSON document. For example: BsonDocument nested = new BsonDocument { { "name", "John Doe" }, { "address", new BsonDocument { { "street", "123 Main St." }, { "city", "Centerville" }, { "state", "PA" }, { "zip", 12345} }} }; This creates a top level document with two elements ("name" and "address"). The value of "address" is a nested BSON document. Add methodsBsonDocument has the following overloaded Add methods:
It is important to note that sometimes the Add methods don't 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. For example: BsonDocument document = new BsonDocument { { "name", name }, { "city", city }, // not added if city is null { "dob", dob, dobAvailable } // not added if dobAvailable is false }; is more compact and readable than: BsonDocument document = new BsonDocument(); document.Add("name", name); if (city != null) { document.Add("city", city); } if (dobAvailable) { document.Add("dob", dob); } If you want to add a BsonNull if a value is missing you have to say so. A convenient way is to use C#'s null coalescing operator as follows: BsonDocument = new BsonDocument { { "city", city ?? BsonConstants.Null } }; The IDictionary overloads initialize a BsonDocument from a dictionary. Each key in the dictionary becames 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 elementsThe recommended way to access BsonDocument elements is to use one of the following indexers:
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: BsonDocument book; string author = book["author"].AsString; DateTime publicationDate = book["publicationDate"].AsDateTime; int pages = book["pages", -1].AsInt32; // default value is -1 BsonArrayThis 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. ConstructorsBsonArray has the following constructors:
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 methodsBson Array has the following Add methods:
Note that the Add method takes a single parameter. To create and initialize a BsonArray with multiple values use any of the following approaches: // traditional approach BsonArray a1 = new BsonArray(); a1.Add(1); a2.Add(2); // fluent interface BsonArray a2 = new BsonArray().Add(1).Add(2); // values argument int[] values = new int[] { 1, 2 }; BsonArray a3 = new BsonArray(values); // collection initializer syntax BsonArray a4 = new BsonArray { 1, 2 }; IndexerArray elements are accessed using an integer index. Like BsonDocument, the type of the elements is BsonValue. For example: BsonArray array = new BsonArray { "Tom", 39 }; string name = array[0].AsString; int age = array[1].AsInt32; The C# DriverUp until now we have been focusing on the BSON Library. The remainder of this tutorial focuses on the C# Driver. Thread safetyOnly a few of the C# Driver classes are thread safe. Among them: 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. MongoServer classThis class serves as the root object for working with a MongoDB server. You will create one instance of this class for each server you connect to. 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 MongoServer, which represents the replica set as a whole. The driver automatically finds all the members of the replica set and identifies the current primary. MongoServer has several properties you can use to find out more about the current state of the replica set (such as Primary, Secondaries, etc...). Instances of this class are thread safe. Connection stringsThe 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. These credentials will be the default credentials for all databases. To authenticate against the admin database append "(admin)" to the username. If you are using different credentials with different databases pass the appropriate credentials to the GetDatabase method. The port number is optional and defaults to 27017. To connect to a replica set 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). The C# Driver is able to connect to a replica set even if the seed list is incomplete. It 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). The options part of the connection string is used to set various connection options. For example, to turn SafeMode on by default for all operations, you could use: mongodb://localhost/?safe=true
As another example, 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: mongodb://server2/?connect=direct;slaveok=true
The full documentation for connection strings can be found at: http://www.mongodb.org/display/DOCS/Connections Create methodTo obtain an instance of MongoServer use one of the Create methods:
For example: string connectionString = "mongodb://localhost";
MongoServer server = MongoServer.Create(connectionString);
Create maintains a table of MongoServer instances it has returned before, so if you call Create again with the same parameters you get the same instance back again. The recommended way to call Create is with a connection string in the MongoDB URL format. MongoConnectionStringBuilder is provided for compatibility with how .NET handles SQL Server connection strings, but we recommend you use the URL format instead. GetDatabase methodYou can navigate from an instance of MongoServer to an instance of MongoDatabase (see next section) using one of the following GetDatabase methods or indexers:
Sample code: MongoServer server = MongoServer.Create(); // connect to localhost MongoDatabase test = server.GetDatabase("test"); MongoCredentials credentials = new MongoCredentials("username", "password"); MongoDatabase salaries = server.GetDatabase("salaries", credentials); 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: var databaseSettings = server.CreateDatabaseSettings("test"); databaseSettings.SlaveOk = true; var database = server[databaseSettings]; 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 methodsSometimes 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 SafeMode off, and you want to query that data in a consistent manner immediately thereafter (with SafeMode off 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: server.RequestStart(database);
// a series of operations that must be performed on the same connection
server.RequestDone();
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. There is actually a slight problem with this example: if an exception is thrown while performing the operations then RequestDone is never called. You could put the call to RequestDone in a finally block, but even easier is to use the C# using statement: using (server.RequestStart(database)) {
// a series of operations that must be performed on the same connection
}
This works because RequestStart returns a helper object that implements IDisposable and calls RequestDone for you. RequestStart increments a counter (for this thread) and RequestDone decrements the counter. 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/RequestDone can be nested and the right thing will happen. Other properties and methodsMongoServer has the following properties:
MongoServer has the following additional methods:
MongoDatabase classThis 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 methodThis 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: MongoDatabase hr = server.GetDatabase("hr"); MongoCollection<Employee> employees = hr.GetCollection<Employee>("employees"); 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: var collectionSettings = database.CreateCollectionSettings<TDocument>("test"); collectionSettings.SlaveOk = true; var collection = database.GetCollection(collectionSettings); 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 methodsMongoDatabase has the following properties:
MongoDatabase has the following additional methods:
MongoCollection<TDefaultDocument> classThis 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> methodTo 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: MongoCollection<BsonDocument> books =
database.GetCollection<BsonDocument>("books");
BsonDocument book = new BsonDocument {
{ "author", "Ernest Hemingway" },
{ "title", "For Whom the Bell Tolls" }
};
books.Insert(book);
If you have a class called Book the code might look like: MongoCollection<Book> books = database.GetCollection<Book>("books"); Book book = new Book { Author = "Ernest Hemingway", Title = "For Whom the Bell Tolls" }; books.Insert(book); InsertBatch methodYou can insert more than one document at a time using the InsertBatch method. For example: MongoCollection<BsonDocument> books;
BsonDocument[] batch = {
new BsonDocument {
{ "author", "Kurt Vonnegut" },
{ "title", "Cat's Cradle" }
},
new BsonDocument {
{ "author", "Kurt Vonnegut" },
{ "title", "Slaughterhouse-Five" }
}
};
books.InsertBatch(batch);
When you are inserting multiple documents InsertBatch can be much more efficient than Insert, specially when using SafeMode. FindOne and FindOneAs methodsTo 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: MongoCollection<Book> books; BsonDocument document = books.FindOneAs<BsonDocument>(); 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 methodsThe 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). Also, by using the QueryWrapper class the query can be of any type that can be successfully serialized to a BSON document, but it is up to you to make sure that the serialized document represents a valid query object. One way to query is to create a QueryDocument object yourself: MongoCollection<BsonDocument> books; var query = new QueryDocument("author", "Kurt Vonnegut"); foreach (BsonDocument book in books.Find(query)) { // do something with book } Another way to query is to use the Query Builder (recommended): MongoCollection<BsonDocument> books; var query = Query.EQ("author", "Kurt Vonnegut"); foreach (BsonDocument book in books.Find(query)) { // do something with book } Yet another way to query is to use an anonymous class as the query, but in this case we must wrap the anonymous object: MongoCollection<BsonDocument> books; var query = Query.Wrap(new { author = "Kurt Vonnegut" }); foreach (BsonDocument book in books.Find(query)) { // do something with book } If you want to read a document of a type that is not the default document type use the FindAs method instead: MongoCollection<BsonDocument> books; var query = Query.EQ("author", "Kurt Vonnegut"); foreach (Book book in books.FindAs<Book>(query)) { // do something with book } Save<TDocument> methodThe 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. For example, you could correct an error in the title of a book using: MongoCollection<BsonDocument> books; var query = Query.And( Query.EQ("author", "Kurt Vonnegut"), Query.EQ("title", "Cats Craddle") ); BsonDocument book = books.FindOne(query); if (book != null) { book["title"] = "Cat's Cradle"; books.Save(book); } The TDocument class must have an Id member to be used with the Save method. If it does not you can call Insert instead of Save to insert the document. Update methodThe Update method is used to update existing documents. The code sample shown for the Save method could also have been written as: MongoCollection<BsonDocument> books; var query = new QueryDocument { { "author", "Kurt Vonnegut" }, { "title", "Cats Craddle" } }; var update = new UpdateDocument { { "$set", new BsonDocument("title", "Cat's Cradle") } }; BsonDocument updatedBook = books.Update(query, update); or using Query and Update builders: MongoCollection<BsonDocument> books; var query = Query.And( Query.EQ("author", "Kurt Vonnegut"), Query.EQ("title", "Cats Craddle") ); var update = Update.Set("title", "Cat's Cradle"); BsonDocument updatedBook = books.Update(query, update); FindAndModify methodUse 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: http://www.mongodb.org/display/DOCS/findAndModify+Command the call to FindAndModify would be written in C# as: var jobs = database.GetCollection("jobs"); var query = Query.And( Query.EQ("inprogress", false), Query.EQ("name", "Biz report") ); var sortBy = SortBy.Descending("priority"); var update = Update. .Set("inprogress", true) .Set("started", DateTime.UtcNow); var result = jobs.FindAndModify( query, sortBy, update, true // return new document ); var chosenJob = result.ModifiedDocument; MapReduce methodMap/Reduce is a way of a 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. var map = "function() {" + " for (var key in this) {" + " emit(key, { count : 1 });" + " }" + "}"; var reduce = "function(key, emits) {" + " total = 0;" + " for (var i in emits) {" + " total += emits[i].count;" + " }" + " return { count : total };" + "}"; var mr = collection.MapReduce(map, reduce); foreach (var document in mr.GetResults()) { Console.WriteLine(document.ToJson()); } Other properties and methodsMongoCollection has the following properties:
MongoCollection has the following additional methods:
MongoCursor<TDocument> classThe 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 cursorThe most convenient way to consume the results of a query is to use the C# foreach statement. For example: var query = Query.EQ("author", "Ernest Hemingway"); var cursor = books.Find(query); foreach (var book in cursor) { // do something with book } You can also use any of the extensions methods defined by LINQ for IEnumerable<T> to enumerate a cursor: var query = Query.EQ("author", "Ernest Hemingway"); var cursor = books.Find(query); var firstBook = cursor.FirstOrDefault(); var lastBook = cursor.LastOrDefault(); Note that 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 itA 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:
For example, if we want to skip the first 100 results and limit the results to the next 10, we could write: var query = Query.EQ("status", "pending"); var cursor = tasks.Find(query); cursor.Skip = 100; cursor.Limit = 10; foreach (var task in cursor) { // do something with task } or using the fluent interface: var query = Query.EQ("status", "pending"); foreach (var task in tasks.Find(query).SetSkip(100).SetLimit(10)) { // do something with task } 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 cursorThe following properties of a cursor are modifiable:
The method names in parenthesis are the corresponding fluent interface methods. The fluent interface also supports additional options that aren't used very frequently and are not exposed as properties:
Other methodsMongoCursor has a few methods used for some special purpose operations:
SafeMode classThere are various levels of SafeMode, and this class is used to represent those levels. SafeMode 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 SafeMode 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. The SafeMode class is no longer immutable. The properties have been made settable to facilitate creation of new instances using object initializer syntax. While it is no longer immutable, SafeMode instances can now be "frozen" to make them immutable at run time. A SafeMode instance is not thread safe until it has been frozen, at which point it becomes thread safe. ConstructorsSafeMode has the following constructors:
Because SafeMode now has more properties than it originally did, we are no longer adding constructors with different combinations of parameters (there would just be too many). The existing constructors are kept for backward compatibility. The recommended way to instantiate an instance of SafeMode is to use the last constructor to initialize all properties from another instance of SafeMode and then use object initializer syntax to set the properties you want to change. For example: var safeMode = new SafeMode(other) { WMode = "majority" }; which creates a new instance of SafeMode with all the same properties as the "other" instance with the WMode changed to "majority". PropertiesSafeMode has the following properties:
MethodsSafeMode has the following methods:
|

PLEASE POST QUESTIONS IN THE USER GROUPS FORUM. Post non-question comments and helpful hints here.
blog comments powered by Disqus