Week 1

What’s MongoDB?

Application Architecture

Javascript Object Notation (JSON)

Dictionary

Array

Mongo Applications

Mongo Shell

Mongo Deamon

Mongo Dump

Mongo Restore

Mongo Schema

Relational Modeling vs Hierarchical Modeling

Traditional ER Modeling

MongoDB modeling

Intro to Schema Design

Hands On

Set it up

Week 2

CRUD & Mongo Shell

Mongo Shell

BSON

CRUD in the Mongo Shell

Exploring the mongo instance

show databases

use

show collections

Inserting new documents

Querying collections

find method

findOne method

Parameters for find methods

Queries

Queries with relational operators

Relational operators on Strings

Relational operators when data type is different.

Querying based on document structure

$exists operator

$type operator

$regex operator

Queries with logical operators

$or operator

$and operator

Querying Arrays

Normal queries (Polymorphic behavior)

$all operator

$in operator

Querying nested documents (the dot notation)

The dot notation

Cursors

pretty() method

hasNext() method

next() method

limit(number) method

sort (document) method

skip(number) method

Chaining cursor methods

Counting on queries

Updating documents

Update Document (whole document replacement)

Update simple field

$set operator

$inc operator

$unset operator

Updating arrays fields

Dot Notation

$push operator

$pop operator

$pushAll operator

$pull operator

$pullAll operator

$addToSet operator

Upserts

Multi-update

Removing documents

Getting started with .NET Driver

MongoDb Client and Connection

POCO Representation

Using attributes

Using BsonClassMap

Using Conventions

MongoDb CRUD

Inserting data

Reading documents

Iterating over the collection

Filtering the collection


MongoDB Training

Week 1

What’s MongoDB?

MongoDB is a scalable database. In this document we will explore the basics traits of mongo db and provide code examples for a blog site (a real world use case).

MongoDB is a non relational DB for JSON documents. By non relational it means that it does not follow the standard Entity Relacion concept as in normal relational databases.

Comparison of MongoDB about Scalability and built-in function against other storage options

Keep in mind that MongoDB:

Application Architecture

Browser (View)

HTTP/HTTPS

WebServer (IIS, Apache, nginx)

MongoDB Driver

TCP

MongoDB Server (mongodb, mongos)

A typical web application has many layers, the application can use the MongoDB driver to talk directly to the MondoDB server.

Javascript Object Notation (JSON)

For a more detailed explanation of JSON check http://json.org/

JSON let us represent a document (usually a key-value collection), and also we can express a collection of documents or a hierarchy of documents as well.

Dictionary

Represents a collection of key-value pairs (also document).

{ a: 1, b:  true, c: “hello” }

Array

Represents a collection of documents.

{ propertyA: 1, propertyB: [ 1, 2, 3 { a: 1, b: true} ]

A mongodb document (or JSON object) is a dictionary which internally contains any combinations of dictionaries and arrays.

Mongo Applications

Mongo Shell

The mongo shell is an application which is deployed among mongo, and it lets interact with the database instances.

Mongo Deamon

This application starts a database instance. Thus, the mongo shell (or our application) can connect to the mongo service.

mongod.exe --smallfiles --noprealloc

Notices that the 32 bit implementation of MongoDB is not recommended because it limits the number of possible directions. Moreover, 2^32 bytes is equals to 4.3GB, but mongodb stores about 2GB. This is because mongodb uses power of 2 sizes for record allocation strategy. Any created record consumes the smallest record than can contain it (32 bytes, 64 bytes, …). Performance is increased at the price of disk space, plus mongodb stores metadata (e.g. indexes) making the 32 bit  implementation to run out of space between 2GB and 4GB.

Mongo Dump

Lets dump the content of a mongodb database into a file.

Mongo Restore

Lets the user restore a dump from a database or perform insert batch from specific types of files.

Mongo Schema

In traditional RDMS (Relational Database Management Systems) each record under the same table is warranty to have the same structure. On the other hand, in mongodb a collection of documents may have different structure. For example following two documents can be stored into the same collection:

{

        “_id” : ObjectId(”E0C0FF102D4045F98001E341E26A9BC8”),

        “name” : “Andrew Erlichson”,

        “city_of_birth” : “Queens”

}

{

        “_id” : ObjectId(“B07FA45955C6419E83F5954E13532B7A”),

        name : “Richard Kreuter”,

        “city_of_birth” : “Chicago”,

        “favorite_color” : “red”

}

Please notice that the last document has an extra value favorite_color which is only present in one document of the collection. This is the flexibility present in a  dynamic schema storage.

Relational Modeling vs Hierarchical Modeling

Traditional ER Modeling

In traditional ER modeling we use entities, and relations, for example for a Web Blog application:

Example of a Blog Storage for a Entity Relation Storage

In the ER model, for listing a blog post, its comments, its tags and authors, the database has to access 5 tables.

MongoDB modeling

Modeling in MongoDB keeps more simple and organic the structures used by the application.

The previous mongo db model may only need to access one collection in order to retrieve all the information related to a blog post, even one document may contain all the information of all the blog post.

Intro to Schema Design

In ER models it is really easy to create a mode by following rules of the third normal form, but in nosql schemas very important questions such as to embed or not to embed need to addressed.

To answer this, take into account how your application works:

For example in our web blog application:

Posts are normally accessed with its author,comments and tags. Comments only belongs to one post. Even though tags will be duplicated, it’s very unlikely that we are going to replace a text in tags. Furthermore, comments are not meant to take longer than 16MB per blog post.

Hands On

Set it up


Week 2

CRUD & Mongo Shell

CRUD item

MongoDB Equivalent

SQL Operator

Create

Insert

INSERT

Read

Find

SELECT

Update

Update

UPDATE

Delete

Remove

DELETE

Mongo Shell

The mongo shell is started by typing mongo in the console or terminal. The mongo shell uses javascript syntax to perform tasks. Additional to the normal Javascript context execution, mongo shell adds extra objects/functions that can be used as valid commands.

BSON

MongoDB uses internally BSON for storing and retrieving information. BSON stands for Binary Javascript Object Notation or simply Binary JSON. In the mongo shell JSON objects (or documents) are typed using JSON sintax, these values are translated to BSON in order to be stored.

BSON is a superset of JSON, this means that it supports all types in JSON and adds some extra for convenience. For example numbers can be mapped to specific BSON types, in the mongo shell this can be done by using constructors:

> NumberLong(1) + NumberLong(3)

In this case the Constructor NumberLong lets the user specify that the number should be using a Long representation in BSON which each language may map to the proper type. Not all the languages have the same types, for example all numbers in JavaScript are number thus long representation may not have much sense. The following are examples of supported data types in BSON

:

BSON is well documented at http://bsonspec.org/.

CRUD in the Mongo Shell

The mongo shell is meant to be used using Javascript and it provides objects and functions to facilitate the interaction with the database.

The mongo shell has an object called db which represents the current database. The db object other than its normal methods and properties, it also holds a property for each collection. A collection is where JSON documents are stored.

Exploring the mongo instance

To explore the mongodb instance, the following commands can be used:

show databases

This command will list all the available databases into the mongo instance.

> show databases

local   0.078125GB

use

the command use and followed by a database name will let you change the current database (db value).

> use conta

switched to db conta

show collections

The show collections command lists all the already created collections in the current database.

> show collections

system.indexes

users

Inserting new documents

Each collection of the db  object can access the method insert, which accepts as parameter the document to be inserted.  For example:

> db.people.insert( { 'name' : 'Smitsh' ,  'age' : 30 , 'profession' : 'hacker' } )

> db.people.insert( { 'name' : 'Luke' ,  'age' : 20 , 'profession' : 'backer' } )

The previous command inserts into the collection people a new document.

MongoDB requires that all the inserted documents has:

Querying collections

find method

Each collection has different find methods to retrieve information. For example:

> db.people.find()

{ "_id" : ObjectId("551a12029db3c3bff558f08b"), "name" : "Smitsh", "age" : 30, "profession" : "hacker" }

{ "_id" : ObjectId("551a12289db3c3bff558f08c"), "name" : "Luke", "age" : 20, "profession" : "backer" }

find method without any parameter will return all the records into a given collection.

findOne method

> db.people.findOne()

{

        "_id" : ObjectId("551a12029db3c3bff558f08b"),

        "name" : "Smitsh",

        "age" : 30,

        "profession" : "hacker"

}

findOne method without any parameter will return the first record it founds into a given collection. It shows the indented document in order to quickly get an understanding of the structure.

Parameters for find methods

mongodb uses JSON documents to specify que query parameters. For example, find and findOne accept as first parameter a JSON document, this document will be used as filter when selecting documents, letting pass documents which matches all fields. For example:

> db.people.find({ name : 'Luke' })

{ "_id" : ObjectId("551a12289db3c3bff558f08c"), "name" : "Luke", "age" : 20, "profession" : "backer" }

The second parameter is also a JSON document, this document defines which values should be returned by the query. For example:

> db.people.find({ name : 'Luke' }, { name : true, profession : 1 , _id : 0} )

{ "name" : "Luke", "profession" : "backer" }

Please notice that _id is always returned, for preventing it to be in the return it should be hidden explicitly.

Queries

A call to find method, rather than an array with all the data in one call, it creates a cursor which holds all the information of the query. Then, at some point the query is executed at the server and returns batches of documents. The queries in the mongo shell accept their parameters by using JSON documents to express query information, as part of the information are relational operators as well as logical operations, among others.

Queries with relational operators

The find and findOne methods accept as first parameter a query expression. If a value is provided for a given field, then it’s used to accept only documents in which holds that value in that given field. However, subdocuments with a relational operators can be also included. For example

>db.scores.find( { score : {$gt : 95} } )

The interpretation of the previous query is a result set with documents in which score value is greater than 95. The subdocument can contain as many operators as needed, the filtered documents must fulfill all the operators. For example:

>db.scores.find( { score : {$gt : 95, $lte : 98} } )

The cursor will iterate over the documents with score greater than 95 and (lower than or equals to 98).

Relational operators on Strings

These relational filters can also be applied to string values, which it apply a lexicographic filter (comparing by character position in UTF-8, and string total length). 

Relational operators when data type is different.

Given the nature of mongodb, in a collection the same field can store different data types in different documents. The filter will define the type of the documents to be taken into account.

Querying based on document structure

There are operators which can be applied to fields in order to filter based on the document structure.

$exists operator

> db.people.find ( { profession : { $exists : true} } )

It will returns documents which have defined the profession field.

$type operator

> db.people.find ( { name : {$type : 2} } )

It will returns documents which have a given field of the specified type. Type are detailed using BSON, types are specified using numeric code from BSON specification http://bsonspec.org/spec.html .

$regex operator

> db.people.find ( { name : {$regex : “a” } } )

It will apply a regular expression in order to filter documents.

Queries with logical operators

By default all the relational operators are combined using and logic, but it’s possible also to specify a logical or. The $or and $and operators are prefix operators, this means they come before the queries that they are going to put together. They take as input an array with query documents they combining.

$or operator

> db.people.find ({$or : [ { name : {$regex : “q”}, email : {$exists : true}} ]  })

For example the previous query will return documents which name contains a ‘q’ or documents with an email field. The $or takes as input an array of query documents.

$and operator

As mentioned earlier all relational operands are already combined using and operator. However it’s possible to make it explicitly as follow:

> db.score.find({$and:[{score:{$lt:60}},{email:{$exists:true}}]})

It will return documents with score between 60 and 70, however because of and is the default, the same query can be expressed as follow:

> db.score.find({{score:{$lt:60},email:{$exists:true}}})

Also notice that you may type

> db.score.find({{score:{$gt:50},score:{$lt:60}}})

However, in this case it won’t filter a range, instead the document which holds the score property will be set twice the value of the property, the first time using {$gt:50} and the second time using {$lt:60}.

Querying Arrays

Fields which are properties are also queryable, the query document can specify a value which should be present into the array.

Normal queries (Polymorphic behavior)

For example, lets suppose that favorites field is an array into the documents of the collection account.

> db.account.find ( { favorites : “pretzels” } )

Thus, the cursor will iterate over the documents in which the array favorite at least contains an entry with the value of “pretzels”. Keep in mind:

$all operator

The $all operator validates that an array field contains a given subset of values, regardless of the order of the values. The $all operator receives a collection of values which defines the subset of values to validate.

> db.accounts.find ( {favorites : {$all : [ ‘pretzels’,‘beer’ ] }} )

The previous query will return all documents in which the favorites field contains the two values: pretzels and beer.

$in operator

The $in operator validates that an array field contains at least one value of given collection.

> db.accounts.find ( { favorites: {$in : [ ‘beer’, ‘ice cream’ ]} } )

The previous query will return all the documents in which the favorites field contains either “beer” or “ice cream” values.

Querying nested documents (the dot notation)

As expected a field which holds a nested document can be queried by providing a value (in this case a document) which matches any of the nested documents of the collection.

For example lets suppose we have inserted the following document:

> db.users.insert( { name : "richard", email: { work : "richard@10gen.com", personal : "kreuter@example.com" } } )

The following query will return the inserted document

> db.users.find ( { email : { work : "richard@10gen.com", personal : "kreuter@example.com" } } )

{ "_id" : ObjectId("551aa6312f764ab3e8f1757e"), "name" : "richard", "email" : {

"work" : "richard@10gen.com", "personal" : "kreuter@example.com" } }

However, we need to match the document exactly as it was inserted, otherwise it the query won’t provide results.

> db.users.find ( { email : { personal : "kreuter@example.com" , work : "richard@10gen.com" } } )

> db.users.find ( { email : { work : "richard@10gen.com" } } )

The previous queries does not return any result, since the subdocument values are not in the same order as they were inserted.

The dot notation

Since it is really difficult to keep in mind the order of the fields in which a subdocument was inserted, the dot notation let us perform a query only by a field of the nested document.

> db.users.find ( { "email.work" : "richard@10gen.com" } )

{ "_id" : ObjectId("551aa6312f764ab3e8f1757e"), "name" : "richard", "email" : { "work" : "richard@10gen.com", "personal" : "kreuter@example.com" } }

Please notice that in the previous query, it’s using "email.work" to specify a field into the nested document to be filtered.

The dot notation can be also applies to arrays of subdocuments.  For example, if we have the following structure:

{ product : "Super Duper-o-phonic",

  price : 100000000000,

  reviews : [ { user : "fred", comment : "Great!" , rating : 5 },

              { user : "tom" , comment : "I agree with Fred, somewhat!" , rating : 4 } ],

  ... }

In order to filter the nested documents from the reviews array field, then it can be performed the following query:

> db.catalog.find({price : {$gt : 10000}, "reviews.rating" : {$gte : 5}})

Cursors

As mentioned earlier, find and findOne methods returns a cursor. The cursor itself contains the information in order to perform the query, but the query won’t be executed until a data access is required.

In the mongo shell cursors are objects, and as any other object in Javascript it has methods and properties that can be used for different purposes. In the mongo shell the cursor can be assigned to a variable as follows:

> cur = db.people.find(); null;

It has been also added null just to prevent the shell of printing the value of the assignment.

pretty() method

It can be attached to the cursor in order to print out indented documents.

> db.people.find({ name : 'Luke' }, { name : true, profession : 1 , _id : 0} ).pretty()

{

"name" : "Luke",

"profession" : "backer"

}

hasNext() method

The hasNext method of the cursor, let us know if the cursor as a next record to be fetched.

> cur.hasNext()

true

next() method

next method fetches the next record to be provided by the cursor.

> cur.next();

{

        "_id" : ObjectId("551aa6312f764ab3e8f1757e"),

        "name" : "richard",

        "email" : {

                "work" : "richard@10gen.com",

                "personal" : "kreuter@example.com"

        }

}

limit(number) method

Limits the number of records returned by the cursor to a given number

sort (document) method

Specifies the order in which results should be returned. The document holds the name of the fields to be sorted, and the order: ascending or descending are set by using a positive or negative number respectively.

> cur.sort( { name : -1 } )

{ "_id" : ObjectId("551aaea12f764ab3e8f1757f"), "name" : "stallman", "email" : { "work" : "stallman@10gen.com", "personal" : "stallman@example.com" } }

{ "_id" : ObjectId("551aa6312f764ab3e8f1757e"), "name" : "richard", "email" : { "work" : "richard@10gen.com", "personal" : "kreuter@example.com" } }

skip(number) method

Ignores a given number of documents in result.

> cur.skip(1)

{ "_id" : ObjectId("551aaea12f764ab3e8f1757f"), "name" : "stallman", "email" : { "work" : "stallman@10gen.com", "personal" : "stallman@example.com" } }

Chaining cursor methods

Of course it’s possible to change some cursor methods such as sort and limit.

> cur.sort( { name : -1 } ).limit(1).skip(1)

{ "_id" : ObjectId("551aaea12f764ab3e8f1757f"), "name" : "stallman", "email" : { "work" : "stallman@10gen.com", "personal" : "stallman@example.com" } }

Keep in mind that sort, and are cursor modifiers (the state of the cursor), they returned the modified cursor. The cannot be applied once data has been retrieved or checked in their existence.

Counting on queries

Collections has also have an special method called count, this method accepts a query document in order to filter the documents that should be taken into account.

> db.users.count( { name: {$regex : "st"} } )

1

Updating documents

Update Document (whole document replacement)

Collections have a method for updating documents called update. The update can accept up to 2 parameters. The first parameter is the query document, used to specify the documents to be affected. The second document is the new value for the document, except by the _id  field which it is immutable.

For example the collection has the following document

{ "_id" : "Texas", "population" : 2500000, "land_locked" : 1 }

and it performs the following update:

db.foo.update({_id:"Texas"},{population:30000000})

The resultant document is:

{ "_id" : "Texas", "population" : 30000000 }

Update simple field

The method update of the collection accepts in its the second parameter operators to specify a nitty-gritty update.

$set operator

$set sets the value of a given field, if the field does not exist in the document then it gets created with the provided value.

For example, updating a given field rather than the entire document.

> db.people.update ( { name : “alice” } , {$set : { age : 30 } })

$inc operator

$inc increases a field by a given value . If the field does not exist then it gets created with the increment step. For example:

> db.people.update ( { name : “alice” }, {$inc : {age : 1}} } )

$unset operator

allows to remove a field (and its value) from a document.

> db.people.update ( { name : “Jones” } , {$unset : { profession : 1 }} );

Updating arrays fields

There are many operators which deal with updating array fields.

Dot Notation

In a similar manner that we can use the dot (.) for specifying a subdocument field, we can also use the dot and followed by a number to indicate the index of the array that we want to update. Give the following document

> db.arrays.insert ( { _id : 0 , a : [ 1, 2, 3, 4 ]} )

the possible update can be performed:

> db.arrays.update( { _id : 0} , {$set : { “a.2”: 5} })

$push operator

Adds an element to the right-hand side of the array.

> db.arrays.update ( {_id:0} , {$push : {a : 6}} )

$pop operator

Removes the rightmost element from an array when the number is positive. or the leftmost elements when the number is negative.

> db.arrays.update ( {_id:0} ,  {$pop : { a : 1 }}

$pushAll operator

Inserts an array of values into a given field.

> db.arrays.update ( {_id:0} , {$pushAll : {a : [5,6,7,8] }} )

$pull operator

Remove a value from the array field, regardless its position.

> db.arrays.update ({_id:0}, {$pull : {a : 5}})

$pullAll operator

Removes any occurrence of value from the array field, regardless their position.

> db.array.update( {_id:0} ,  {$pullAll : { a : [7,8] }} )

$addToSet operator

Adds a value to an array field. The logic for adding the value prevents duplicated entries into the array, (aka set).

> db.arrays.update ({_id:0} , {$addToSet : {a : 5}})

$addToSet is idempotent, which means that after calling the function many times with the same parameters only the first call will take effect.

Upserts

An upsert is an update which can also insert the document if any document does not meet the query document criteria. The update receives a third parameter which it is a options document.

> db.people.update ( { name : “George”} ,  {$set : { age: 40} } , {upsert : true} )

In the previous example, if no document is found, then a new document will be created and it will have set the age to 40, and name equals to “George”. The upsert will try to infer as much as possible the fields of the new document, but some may left out if they undetermined.

Multi-update

A multiple document can be updated when the query document matches multiple documents, by default the update will only affect the first match, but setting the option multi to true the update will affect all the matching documents.

> db.people.update ( {} , {$set : { title : “Sr”}} , {multi : true} )

Keep in mind that mongodb by default only updates one document, which differs from traditional SQL commands which affects all the matching records.

Also, the multi-update does not block the table, which means that other modifications can happen while the multi-update is happening. This is because of the pausing-yielding feature, it means it updates a batch of documents, pauses, yield the thread to another task, and the continue, and repeats the process until it is done.

Removing documents

All the collections have a method called removed, in which the first argument is the query document.

>  db.people.remove ( { name : “maria” } )

An empty query document will remove all the documents of the collection

>  db.people.remove ( { } )

However it is faster to remove the collection, because removing all the documents implies an one-by-one update in the collection (and regenerate the indexes).  To remove the collection drop method can be used.

> db.people.drop()

The removing documents does not block the collection, which means, that the collection can be being deleted while other process are querying it or updating it.

Getting started with .NET Driver

The .NET libraries can be downloaded directly from the mongodb website, but the most simple way to get them, it is thru nuget. By the time this document was written nuget has three mongodb package, and version 2.0.0.0 was just released. The nuget packages available are:

MongoDb Client and Connection

Root object for accessing mongodb, by default it connects to the local instance using default settings. The class itself is thread-safe, thus it can be used in in a static field or singleton as well as on each instance. When using MongoClient class If the mongodb instance to be accessed is not using default settings then it is possible to use an instance of MongoClientSettings  in order to specify connection parameters. Moreover, it’s possible to specify the connection settings by using a connection string ( e.g.: “mongodb://localhost:27017,localhost:27018/?replicaSet?funny” ) Once the connection is opened. then the first step is to get a instance of the database, and the a collection as the following snippet shows:

var connectionString = @“mongodb://localhost:27017”’;

var client = new MongoClient(connectionString);

var db = client.GetDatabase(“test”);

var col = db.GetCollection(<BsonDocument>(“people”);

POCO Representation

The javascript objects will be translated to objects in C#. Normally objects which only withholds data are known as Plain Old CLR Objects (or POCO for short). It’s possible to instruct BsonSerializer class how the mongo documents have to be deserialize

Using attributes

class Person {

        public ObjectId Id {get;set;}

        [BsonElement(“name”)] // Specifies the name of the property

        public string Name {get;set;}

        [BsonRepresentation(BsonType.String)] // Specifies the Bson Type to store the value

        public int Age {get;set;}

}

Using BsonClassMap

The same specifications as well as many others can be also done by using the BsonClassMap class. As follows:

BsonClassMap.RegisterClassMap<Person>( cm =>

{

        cm.AutoMap();

        cm.MapMember(x => x.Name).SetElementName(“Name”);

});

Using Conventions

Finally it’s possible to specify a set of conventions. A convention is represented by a ConventionPack class. This applies for all

var conventionPack = new ConventionPack();

conventionPack.Add(new CamelCaseElementNameConvention());

ConventionRegistry.Register(“camelCase”, conventionPack, type => true);

MongoDb CRUD

Inserting data

var client = new MongoClient();

var db = client.GetDatabase(“test”);

var col = db.GetCollection<BsonDocument>(“people”);

var doc = new BsonDocument

{

        {“Name”, “Smitch”},

        {“Age”, 30},

        {“Profession”, “Hacker”}

};

var doc2 = new BsonDocument {

        {“SomethingElse”,true}

};

await col.InsertOneAsync(doc);

await col.InsertManyAsync(new [] { doc, doc2});

Moreover instead of using the BsonDocument class we can use one of the POCO classes available in our application. Take into consideration that once the document is inserted the property ID is populated by MongoDB, thus calling once again the insert method with the same object and collection, then it’s likely to produce an exception.

Reading documents

Iterating over the collection

There are multiple options for retrieving documents, the one which offers more granularity is by requesting a cursor, looping over the batches of documents, and then looping on each document.

var client = new MongoClient();

var db = client.GetDatabase(“test”);

var col = db.GetCollection<BsonDocument>(“people”);

// Request a cursor to iterate over the collection

using (var cursor = await col.Find(new BsonDocument()).ToCursorAsync())

{

        // Request a batch of documents to iterate over them

        while (await cursor.MoveNextAsync())

        {

                // Iterates over the current batch of documents

                foreach(var doc in cursor.Current)

                {

                        Console.WriteLine(doc)

                }

        }

}

Alternatively, it’s possible to perform a simpler query, by using find method with the drawback that all the result set is going to be temporarily in memory.

var list = await col.Find(new BsonDocument()).ToListAsync();

foreach (var doc in list)

{

        Console.WriteLine(doc);

}

At last it’s possible to iterate over documents by using the helper method ForEachAsync

await col.Find(new BsonDocument()).ForEachAsync( doc => Console.WriteLine(doc));

Filtering the collection
Find method overloads

The Find method has many overloads, they normally accept a document which sets the filters for the query. The document can be a BsonDocument, or an JSON into a String, this happens because of the implicit conversions provided by MongoDb .NET Driver.

var list = await col.Find(new BsonDocument(“name”, “Smith”)).ToListAsync();

foreach (var doc in list)

{

        Console.WriteLine(doc);

}

Also in the same way as it works in the mongodb shell, in here we can use the operators in the document, such as:

var list = await col.Find(new BsonDocument(“age”, new BsonDocument(“$lt”,30))).ToListAsync();

foreach (var doc in list)

{

        Console.WriteLine(doc);

}

In addition, it’s possible to combine the filters as follows:

var filter = new BsonDocument(“$and”, new BsonArray{

        new BsonDocument(“$lt”,30),

new BsonDocument(“Name” : “Smith”),

});

An alternative it’s using Builders as follows:

var builder = Builders<BsonDocument>.Filter;

var filter = builder.Lt(“Age”,30);

Also more complex filters can be created using builders, such as:

var filter = builder.And(builder.Lt(“Age”,30), !builder.Eq(“Name”,”Smith”));

When using POCOs it’s only matter of replacing BsonDocument with the proper POCO type. Moreover some expression can be expressed in a better way:

var filter = builder.And(builder.Lt(person => person.Age ,30), !builder.Eq(person => person.Name ,”Smith”));

Also, once the collection is typed, it can support expressions as parameters. For example

var list = await col.Find ( p => p.Age < 30 && p.Name != “Smith” );