Post

Querying Mongo in C#

A few example of how to use MongodoDB drivers in C# and LINQ

In this blog post, I’ll show so example on how to use C# MongoDB drive to querying a collection called “movies”, available in the sample data provided by MongoDB when you create a new cluster.

First, you’ll need to install the C# MongoDB driver.

1
dotnet add package MongoDB.Driver

Then, set your environment variable ATLAS_URI param, it should look something like this:

1
ATLAS_URI="mongodb+srv://${MFLIX_DEMO_USER}:${MFLIX_DEMO_PASS}@<YOUR_CLUSTER_URI>.mongodb.net/?retryWrites=true&w=majority"`

Our collection conatains movie documents from the last 30 40 years, and each record looks something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
{
  "_id": {"573a1398f29313caabce9682"
  },
  "plot": "A young man is accidentally sent 30 years into the past in a time-traveling DeLorean invented by his friend, Dr. Emmett Brown, and must make sure his high-school-age parents unite in order to save his own existence.",
  "genres": [
    "Adventure",
    "Comedy",
    "Sci-Fi"
  ],
  "runtime": 116,
  "metacritic": 86,
  "rated": "PG",
  "cast": [
    "Michael J. Fox",
    "Christopher Lloyd",
    "Lea Thompson",
    "Crispin Glover"
  ],
  "poster": "https://m.media-amazon.com/images/M/MV5BZmU0M2Y1OGUtZjIxNi00ZjBkLTg1MjgtOWIyNThiZWIwYjRiXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SY1000_SX677_AL_.jpg",
  "title": "Back to the Future",
  "fullplot": "Marty McFly, a typical American teenager of the Eighties, is accidentally sent back to 1955 in a plutonium-powered DeLorean \"time machine\" invented by slightly mad scientist. During his often hysterical, always amazing trip back in time, Marty must make certain his teenage parents-to-be meet and fall in love - so he can get back to the future.",
  "languages": [
    "English"
  ],
  "released": {
    "$date": "1985-07-03T00:00:00Z"
  },
  "directors": [
    "Robert Zemeckis"
  ],
  "writers": [
    "Robert Zemeckis",
    "Bob Gale"
  ],
  "awards": {
    "wins": 19,
    "nominations": 24,
    "text": "Won 1 Oscar. Another 18 wins & 24 nominations."
  },
  "lastupdated": "2015-09-12 00:29:36.890000000",
  "year": 1985,
  "imdb": {
    "rating": 8.5,
    "votes": 636511,
    "id": 88763
  },
  "countries": [
    "USA"
  ],
  "type": "movie",
  "num_mflix_comments": 0
}

We’re going to run 3 queries:

  1. Find the info of the classic “Back to the future” movie
  2. Find all the movies Michael Keaton played in between 1985-1990
  3. Sum all the runtime of movies played by Ryan Reynolds in our collection

Plain MongoDB Query Language (MQL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use('sample_mflix');

db.movies.findOne({title: "Back to the Future"})

db.movies.find({
    year: {$gte: 1985, $lt: 1990},
    cast: {$in: ["Michael Keaton"]}
})

db.movies.aggregate([
    {$match: {cast: {$in: ["Ryan Reynolds"]}}},
    {$set: {cast: "Ryan Reynolds"}},
    {$group: {_id: "cast", sum: {$sum: "$runtime"}}}
])

C# using a regular filters

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using System;
using MongoDB.Driver;
using MongoDB.Bson;

var connectionString = Environment.GetEnvironmentVariable("ATLAS_URI");

var client = new MongoClient(connectionString);

var collection = client.GetDatabase("sample_mflix").GetCollection<BsonDocument>("movies");

// Find movie by title

var filter = Builders<BsonDocument>.Filter.Eq("title", "Back to the Future");

var document = collection.Find(filter).First();

Console.WriteLine(document);

// Michael Keaton movies in the 80's:

filter = Builders<BsonDocument>.Filter.And(
    Builders<BsonDocument>.Filter.Gte("year", 1985),
    Builders<BsonDocument>.Filter.Lte("year", 1990),
    Builders<BsonDocument>.Filter.AnyIn("cast", new BsonArray { "Michael Keaton" })
);

Console.WriteLine("\nMichael Keaton movies in the 80's:");
var cursor = collection.Find(filter).ToCursor();
while (cursor.MoveNext())
{
    foreach (var doc in cursor.Current)
    {
        Console.WriteLine("Title: {0}, Year: {1}", doc["title"], doc["year"]);
    }
}

// Ryan Reynolds Screen time

Console.WriteLine("\n Ryan Reynolds Screen time");

var pipeline = new BsonDocument[]
{
    new BsonDocument("$match", new BsonDocument("cast", "Ryan Reynolds")),    
    new BsonDocument("$group", new BsonDocument("_id", "Ryan Reynolds")
        .Add("totalRuntime", new BsonDocument("$sum", "$runtime")))
};

var result = collection.Aggregate<BsonDocument>(pipeline).FirstOrDefault();

if (result != null) {
    var totalRuntime = result.GetValue("totalRuntime", new BsonInt32(0));
    Console.WriteLine("Total runtime of movies with Ryan Reynolds: {0}", totalRuntime);
}

C# using LINQ

When using Linq, you’ll need to define the Movie object we’re refering too. Here is a sample of Movie definition file:

Movie.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// Movie.cs
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;

[BsonIgnoreExtraElements] // When deserializing, ignore fields that weren't specified here
public class Movie {

    [BsonId] // "This is the ID field"
    [BsonRepresentation(BsonType.ObjectId)] // "It should be represented as Mongo object Id"
    public string Id { get; set; }

    [BsonElement("title")]
    public string Title { get; set; } = null!;

    [BsonElement("year")]
    public int Year { get; set; }

    [BsonElement("runtime")]
    public int Runtime { get; set; }

    [BsonElement("plot")]
    [BsonIgnoreIfNull]
    public string Plot { get; set; } = null!;

    [BsonElement("cast")]
    [BsonIgnoreIfNull] // "When serializing, don't output if it's null. On deserializing, it will be null"
    public List<string> Cast { get; set; } = null!;

}

Program.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System;
using System.Text.Json;

MongoClientSettings settings = MongoClientSettings.FromConnectionString(
    Environment.GetEnvironmentVariable("ATLAS_URI")
);

settings.LinqProvider = LinqProvider.V3;

MongoClient client = new MongoClient(settings);

IMongoCollection<Movie> moviesCollection = client.GetDatabase("sample_mflix").GetCollection<Movie>("movies");

Console.WriteLine("Back to the future!");
IMongoQueryable<Movie> backToFuture =
            from movie in moviesCollection.AsQueryable()
            where movie.Title == "Back to the Future"
            select movie;

var entry = backToFuture.FirstOrDefault();
string strJson = JsonSerializer.Serialize<Object>(entry);
Console.WriteLine(strJson);

Console.WriteLine("\nMichael Keaton movies in the 80's:");

IMongoQueryable<Movie> michaelKeatonMovies =
            from movie in moviesCollection.AsQueryable()
            where movie.Year >= 1985 && movie.Year < 1990
            where movie.Cast.Contains("Michael Keaton")
            select movie;

foreach(Movie film in michaelKeatonMovies) {
    Console.WriteLine("{0}: {1}", film.Title, film.Year);
}


var ryanReynTimeOnScreen = 
            from movie in moviesCollection.AsQueryable()
            where movie.Cast.Contains("Ryan Reynolds") from cast in movie.Cast            
            where cast == "Ryan Reynolds"
            group movie by cast into g
            select new { Cast = g.Key, Sum = g.Sum(x => x.Runtime) };

foreach(var result in ryanReynTimeOnScreen) {
    Console.WriteLine("\n{0} appeared on screen for {1} minutes!", result.Cast, result.Sum);
}

Additional Resources

Sparked you’r interest? Want to read more? Here are a few places to continue your MongoDB C# journey:

C# On Mac - Quick Start

Mongo Driver - Quick Start C#

LINQ

How to Create a .NET Core App with MongoDB Atlas

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.