Channels ▼
RSS

Global Developer

MongoDB with C#


Both the typed and untyped query builders provide a method for each query operator in the MongoDB query language. You can easily explore the available operators using a tool such as MongoVUE to discover them, then using IntelliSense in Visual Studio to check the available method names that are equivalent to each operator. Whenever I have to build a query using the typed query builder and I don't remember the available operators, I use the Object Browser and check the methods available for MongoDB.Driver.Builders.Query<TDocument>. The documentation provides the equivalent MongoDB operator. For example, the GTE<TMember> method tests whether the value of the name element is greater than or equal to the provided value and is equivalent to the $gte operator (see Figure 11).

the Object Browser in Visual Studio
Figure 11: Checking the documentation for the MongoDB.Driver.Builders.Query<TDocument>.GTE<TMember> method in the Object Browser in Visual Studio.

The following MongoDB document query retrieves the first 50 games that were played and have a release date equal or greater than January 1, 2013. The results are ordered by release_date in descending order. You can run the query in the MongoDB shell or you can build it with MongoVUE (Figure 12):

  db.games.find(
      { "release_date" : { "$gte" : ISODate("2013-01-01T00:00:00Z") }, 
        "played" : true }
    )
    .limit(50).sort(
	  { "release_date" : -1 }
    );

MongoVUE
Figure 12: The find document query criteria with the specified sort and limit options in MongoVUE.

The following lines use the typed query builder (Query<Game>) to build the previously shown JavaScript query document in C#. Notice that the SetSortOrder and SetLimit methods specify the sort and limit options for the MongoDB cursor generated by the FindAs<Game> method with the typed query playedGamesQuery as a parameter. The use of a typed builder for specifying a sort order (SortBy<Game>) allows the code to use the properties defined in the Game class for the desired sort key with a lambda expression. Then, a foreach loop writes the values for some properties of each retrieved Game instance to the console.

var playedGamesQuery = 
    Query.And(
        Query<Game>.GTE(g => g.ReleaseDate, new DateTime(2013, 01, 01)),
        Query<Game>.EQ(g => g.Played, true)
    );

var playedGames = games
    .FindAs<Game>(playedGamesQuery)
    .SetSortOrder(SortBy<Game>.Descending(g => g.ReleaseDate))
    .SetLimit(50);

foreach (var playedGame in playedGames)
{
    //// Do something with each played game
    Console.WriteLine("Release date: {0}. Name: '{1}'",
        playedGame.ReleaseDate,
        playedGame.Name);
}

The MongoDB C# driver 1.4 release introduced support for LINQ, which has since been enhanced. LINQ is a good option when you don't want to spend time learning the MongoDB native query operators and syntax. However, you must take into account that not all the LINQ queries have a reasonable translation to an equivalent MongoDB query, and you will definitely have to work with MongoDB native queries when you want to take full advantage of MongoDB features. In fact, you can inject native MongoDB queries into a LINQ query if needed.

The following lines get a reference to the games collection object and call the AsQueryable method to build a LINQ query that just retrieves the first Game instance with the name equal to "Invaders 2013" or a null value if none are found. The LINQ query will produce an expression tree that the MongoDB driver will translate to an equivalent MongoDB query at runtime:

  var games = db.GetCollection<Game>("games");
  var foundGame = games.AsQueryable().FirstOrDefault(g => g.Name == "Invaders 2013");

The previously shown lines are equivalent to the use of the native typed query builder that called the FindOne method:

  var games = db.GetCollection<Game>("games");
  var gameQuery = Query<Game>.EQ(g => g.Name, "Invaders 2013");
  var foundGame = games.FindOne(gameQuery);

It is also possible to build the query that retrieves the first 50 games that were played and have a release date equal or greater than January 1, 2013 with a LINQ query:

  var dateTimeFrom = new DateTime(2013, 01, 01);
  var playedGames =
      games.AsQueryable()
      .Where(g => (g.ReleaseDate >= dateTimeFrom) && g.Played)
      .OrderByDescending(g => g.ReleaseDate)
      .Take(50);

This imperative LINQ query is equivalent to the following declarative LINQ query, which also translates to a MongoDB query document:

  var playedGames =
      (from game in games.AsQueryable()
          where (game.ReleaseDate >= dateTimeFrom) && game.Played
          orderby game.ReleaseDate descending
          select game).Take(50);

If you don't want to work with your domain classes because the document schemata are completely dynamic, you can work with generic BsonDocument instances and use strings to specify the field names in the queries. In order to retrieve the field values, you must call the GetElement method with the desired field name as a parameter (Figure 13). Recall that the BsonDocument is composed of field-value pairs, and the value might be an embedded document.

var dateTimeFrom = new DateTime(2013, 01, 01);
var gamesBson = db.GetCollection("games");
var playedGamesQueryBson =
    Query.And(
        Query.GTE("release_date", dateTimeFrom),
        Query.EQ("played", true)
    );

var playedGamesBson = gamesBson
    .Find(playedGamesQueryBson)
    .SetSortOrder(SortBy.Descending("release_date"))
    .SetLimit(50);

foreach (var playedGameBson in playedGamesBson)
{
    //// Do something with each played game
    Console.WriteLine("Release date: {0}. Name: '{1}'",
        playedGameBson.GetElement("release_date").Value,
        playedGameBson.GetElement("name").Value);
}

MongoVUE find document query criteria
Figure 13: The find document query criteria with the specified sort and limit options in MongoVUE.

Conclusion

In this article, I've shown how to start working with a MongoDB GUI tool and with the C# driver in a Windows console application. I've explained several options for generating your own domain classes and mapping them to their underlying MongoDB document-oriented schema. I've also provided examples of queries using the different options that the MongoDB C# driver offers. In the next article, I'll explain how to perform other operations with the MongoDB C# driver in a more complex application.


Gaston Hillar is an expert in Windows-based programming who writes frequently for Dr. Dobb's.


Related Articles

Getting Started with MongoDB

NoSQL Options Compared


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Video