Skip to content

Instantly share code, notes, and snippets.

@a3dho3yn
Last active June 13, 2024 14:12
Show Gist options
  • Save a3dho3yn/91dcc7e6f606eaefaf045fc193d3dcc3 to your computer and use it in GitHub Desktop.
Save a3dho3yn/91dcc7e6f606eaefaf045fc193d3dcc3 to your computer and use it in GitHub Desktop.
MongoDB C# Driver Cheat Sheet

MongoDB C# Driver Cheat Sheet

(C) 2015 by Derek Hunziker, (C) 2017 by AppsOn

As of releasing MongoDB 3.4 and C# Driver v2.4, original cheatsheet by Derek is outdated. In addition, it has some deficiencies like connecting to MongoDB, creating indexes, etc. This updated version works fine with C# Driver v2.4.7 and MongoDB v3.4.

Setup

Define Document Models

Note: Defined models and collections will be used in entire cheatsheet.

[BsonIgnoreExtraElements]
public class User {
    [BsonId]
    public int Id { get; set } // It's better to use ObjectId, we used int for simplicity
    public int Age { get; set; }
    public string Name { get; set; }
    public Address Address { get; set; }
    public List<string> AliasNames { get; set; }
    public List<Account> Accounts { get; set; }
    DateTime CreatedOn { get; set; }
    DateTime ModifiedOn {get; set; }
}

Connect To Database

// Default connection, localhost:27017
var db = MongoClient();

// With Connection String
var db = MongoClient("http://localhost:27017");

// With MongoUrl Builder
var url = MongoUrl.Create("http://localhost:27017");
var db = MongoClient(url);

Get Collection

var collection = db.GetCollection<User>("users");

Insert

Basic Insert

var user = new User
{ 
    Name = "Hossein",
    Email = "[email protected]"
};

// Basic Insert
collection.InsertOne(user);

// With Write Concern
collection.WithWriteConcern(WriteConcern.WMajority).InsertOne(user);

Insert w/ ID

var user = new User {
    Id = 10,
    Name = "Hossein",
    Email = "[email protected]"
}
collection.InsertOne(user);

Insert Nested

var user = new User {
    Name = "Hossein",
    Email = "[email protected]",
    Address = new Address {
        City = "Portland",
        State = "OR",
        Zip = "97232"
    }
}
collection.InsertOne(user);

Bulk Insert

var users = new []
{
    new User { Name = "Danial", Email = "[email protected]" },
    new User { Name = "Bahar", Email = "[email protected]" },
    new User { Name = "Shadi", Email = "[email protected]" }
};
collection.InsertMany(users);

Filters

Find, update and removing documents use filters, which can be made by filter definition builder.

var builder = Builders<User>.Filter;

Basic Filter

// Empty Filter (matches all)
var empty = builder.Empty;

// Filter by field
var idFilter = builder.Eq(u => u.Id, 10);

// Filter by field with list of desired values
var idListFilter = builder.In(u => u.Id, new [] { 10, 14 });

You can use Gt (<), Lt (>), Ne (!=), Lte (<=), Gte (>=) filters, just like Eq (==).

Embedded Document/Array Filter

// Filter by embedded document's field
var stateFilter = builder.Eq(u => u.Address.State, "OR");

// Filter by array element
var aliasFilter = builder.AnyEq(u => u.AliasNames, "a3dho3yn");

// Filter by array element's field
var accountFilter = builder.ElemMatch(u => u.Accounts, acc => acc.Provider == "GitHub");

// Filter by array element in desired values
var aliasFilter = builder.AnyIn(u => u.AliasNames, new [] { "a3dho3yn", "hossein" });

// Filter by all array elements
var aliasFilterAll = builder.All(u => u.AliasNames, new [] { "a3dho3yn", "hossein" });

There are AnyXx modifiers, where Xx is Gt, Lt, ... (just like single field filters).

Field Properties Filter

// Filter by field existance
var hasNameFieldFilter = builder.Exists(u => u.Name);

// Filter by field type
var idTypeFilter = builder.Type(u => u.Id, BsonType.ObjectId);

Regular Expression Filter

// Filter with regular expression
var pattern = new BsonRegularExpression("yn$");
var nameFilter = builder.RegEx(u => u.Name, pattern);

Combine Filters

You can combine filters with bitwise operators (e.g. &, |) or use builders' methods.

var idAndStateFilter = builder.And(new [] {idFilter, stateFilter}); // == idFilter & stateFilter
var idOrStateFilter = builder.Or(new [] {idFilter, stateFilter}); // == idFilter | stateFilter

Find

Basic Find

Find command will return an iterator, which can be used to retrieve documents.

var cursor = collection.Find(stateFilter);

// Find One
var user = cursor.FirstOrDefault();

// Find All
List<User> users = cursor.ToList();

Sort, Skip, Limit

We use sort definition builder to define sort order.

var sort = Builders<User>.Sort.Ascending(u => u.Name).Descending(u => u.Age);
var cursor = collection.Find(filter).Sort(sort).Skip(5).Limit(10);

Projection

We use porojection definition builder to define how documents will be represented.

var builder = Builders<User>.Projection;
var project = builder.Include(u => u.Name).Exclude(u => u.Id);
var cursor = collection.Find(filter).Project(project);

An alternative way to make projections is using Expressions: builder.Expression(u => new { u.Name });.

Update

Update, needs a filter definitin to find document and an update definition to define which fields and how will change.

Updates can affect one or many documents:

var cursor = collection.UpdateOne(filter, update);
var cursor = collection.UpdateMany(filter, update);

Update Definition

var builder = Builders<User>.Update;

Basic Updates

// Set field
var setName = builder.Set(u => u.Name, "Hossein");

// Unset field
var unsetName = builder.UnSet(u => u.Name);

// Increment field
var incAge = builder.Inc(u => u.Age);

// Current Date
var updateModification = builder.CurrentDate(x => x.ModifiedOn);

There are Mul(tiply), BitwiseAnd, BitwiseOr and BitwiseXor that can be used just like Set operator.

Min/Max

Min and Max operators will modify fields toward min/max value. So, they will update field only if it's value is respectivele greater/less than provided value.

var min = builder.Min(u => u.Age, 18) // Updates field if Age > 18
var max = builder.Max(u => u.Age, 18) // Updates field if Age < 18

Rename Field

var rename = builder.Rename(u => u.Id, "UserId");

Update Array Fields

// Push
var push = builder.Push(u => u.AliasNames, "a3d");

// Pop
var pop = builder.Pop(u => u.AliasNames);

// Pull: removes elements matching value
var pull = builder.Pull(u => u.AliasNames, "a3d");

// Pull All: removes elements matches any values in list
var pullAll = builder.PullAll(u => u.AliasNames, new [] { "a3dho3yn", "hossein" });

// Add To Set
var addToSet = builder.AddToSet(u => u.AliasNames, "a3d");

AddToSet, deals with arrays as sets, and adds elements to an array only if it do not already exist.

Set On Insert

Provided value only used on insert. Then, setting upsert flag and using SetOnInsert is equal to Find Or Create.

var setOnInsert = builder.SetOnInsert(u => u.Name, "Farid");

Upsert

Upsert, will insert new document if it fails in finding a document.

var options = new UpdateOptions() {IsUpsert = true};
collection.UpdateOne(filter, update, options);

Replace (Wholesale Update)

var user = new User() {
    Id = 10,
    Name = "Hamed",
    Email = "[email protected]",
};
var filter = Builders<User>.Filter.Eq(u => u.Id, 10);
collection.ReplaceOne(filter, user);

Remove

Basic Remove

collection.DeleteMany(filter);

Remove One

collection.DeleteOne(filter);
@uuuus
Copy link

uuuus commented Oct 22, 2019

Hi @a3dho3yn,
I am trying to sort with text search, but getting error: MongoDB.Driver.MongoCommandException : Command find failed: $and/$or/$nor must be a nonempty array.
I want to sort text search result by Title ascending.
Code is:
var filter = Helpers.BuildFilters(query);
var projection = Builders.Projection.MetaTextScore("Score");
var sort = Builders.Sort.Ascending("Title");
var collection = _db.GetCollection(_collectionName);
var result = await collection.Find(filter).Project(projection).Sort(sort).Skip(query.Offset ?? 0).Limit(query.PageSize ?? 1000).ToCursorAsync(token);
How to fix it?

P.S. It is working when:
sort = Builders.Sort.MetaTextScore("Score");

@kherona
Copy link

kherona commented May 24, 2020

Perfect thanks. Very helpful considering how outdated/incomplete most MongoDb articles are.

@diegosasw
Copy link

Having problems with updating a value within a list that is also within a list that is also within a list... (3 nested levels, think of buildings that contain floors that contains doors, and I'm trying to modify some list at that specific door)

Does anybody have a sample of something similar with the latest c# driver?

@jcpham81
Copy link

Thanks!! So helpful

@alexbenitez
Copy link

Awesome Cheat Sheet!

I have a question about "upserting" an item within an document array.

I have a collection with documents like this:

{
    "_id" : "a7a7d52e-3d9c-98bb-907f-07beaa2e8903",
    "code" : "Keywords",
    "itemArray" : [ 
        {
            "_id" : "26426253-5692-4bf0-a3cf-31876dc49b0a",
            "code" : "key1",
            "textEnglish" : "key650",
            "textFrench" : "key650",
        }, 
        {
            "_id" : "ef21cfa8-58a4-4466-ab0e-5ef9e27d8223",
            "code" : "key2",
            "textEnglish" : "key650",
            "textFrench" : "key650",
        }, 
        {
            "_id" : "2ae81850c-baa1-438a-b96f-d555620a8aa4",
            "code" : "key3",
            "textEnglish" : "key650",
            "textFrench" : "key650",
        }
    ]
}

I would like to "upsert" itemArray items based on the item id or code (if none is found then insert the item to the array)

I have no problem adding as follows:

await Collection
                    .FindOneAndUpdateAsync(x => x.Id == "a7a7d52e-3d9c-98bb-907f-07beaa2e8903"
                    builder.Push(x => x.ItemArray, item));

or updating an existing one

 var result  = await Collection
                    .FindOneAndUpdateAsync(x => x.Id == "a7a7d52e-3d9c-98bb-907f-07beaa2e8903" && x.ItemArray.Any(it => it.Id == item.Id || it.Code == item.Code), 
                    builder.Set(x => x.ItemArray[-1], item)); 

but having problems trying to use SetOnInsert so I can upsert atomically in one instruction.

What would be the best approach to update an existing array item (based on some criteria) or insert if not found atomically?

@tindecken
Copy link

Thanks a lot for this one. It helps me too much.

@shashikantpawar21
Copy link

pull is not worked for me

@votanliem
Copy link

if I need to get an account list only. how to do?
ex:
var users = new []
{
new User { Name = "Danial", Email = "[email protected]", accounts{ new [] { new Account { id="1", Provider ="GitHub"}, id="2", Provider ="microsoft"}, id="3", Provider ="google"}}
new User { Name = "Bahar", Email = "[email protected]" ,", accounts{ new [] { new Account { id="4", Provider ="GitHub"}, id="5", Provider ="microshop"}, id="6", Provider ="facebook"}} },
new User { Name = "Shadi", Email = "[email protected]", accounts{ new [] { new Account { id="7", Provider ="twitter"}, id="8", Provider ="microshop"}, id="9", Provider ="facebook"}} }
};
// can someone help me query the list account with condition User have acc.Provider == "GitHub")
var builder = Builders.Filter;
var accountFilter = builder.ElemMatch(u => u.Accounts, acc => acc.Provider == "GitHub");
var cursor = collection.Find(accountFilter);
// Find account list
List accounts = cursor.ToList();
//

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment