Expressions

Many methods in the driver accept expressions as an argument.

For the rest of this page, we’ll use the following class:

class Person
{
    public string Name { get; set; }

    public int Age { get; set; }

    public Dictionary<string, Person> Children { get; set; }

    public IEnumerable<Pet> Pets { get; set; }

    public int[] FavoriteNumbers { get; set; }

    public HashSet<string> FavoriteNames { get; set; }

    public DateTime CreatedAtUtc { get; set; }

    public int PermissionFlags { get; set; }
}

class Pet
{
    public string Name { get; set; }
}

Filters

We’ll walk through the supported expressions below. The tests are also a good reference.

Comparison

See the MongoDB documentation for more information on each operator.

$eq

Find(p => p.Name == "Jack")

becomes:

{ Name: 'Jack' }

Note
This is the short form for equality. Depending on context, this might generate { Name: { $eq: 'Jack' } }.

$gt

Find(p => p.Age > 10);
{ Age: { $gt: 10 } }

$gte

Find(p => p.Age >= 10);
{ Age: { $gte: 10 } }

$lt

Find(p => p.Age < 10);
{ Age: { $lt: 10 } }

$lte

Find(p => p.Age <= 10);
{ Age: { $lte: 10 } }

$ne

Find(p => p.Age != 10);
{ Age: { $ne: 10 } }

$in

int[] localAges = new [] { 10, 20, 30 };
Find(p => localAges.Contains(p.Age));
{ Age: { $in: [10, 20, 30] } }
int[] localNames = new [] { "Fluffy", "Scruffy" };
Find(p => p.Pets.Any(i => localNames.Contains(i.Name));
{ "Pets.Name": { $in: ["Fluffy", "Scruffy"] } }
int[] localNumbers = new [] { 30, 40 };
Find(p => localNumbers.Any(i => p.FavoriteNumbers.Contains(i));
{ FavoriteNumbers: { $in: [30, 40] } } 

$nin

int[] localAges = new [] { 10, 20, 30 };
Find(p => !localAges.Contains(p.Age));
{ Age: { $nin: [10, 20, 30] } }

$bitsAllClear

Find(p => (p.PermissionFlags & 7) == 0);
{ PermissionFlags: { $bitsAllClear: 7 } }

$bitsAllSet

Find(p => (p.PermissionFlags & 7) == 7);
{ PermissionFlags: { $bitsAllSet: 7 } }

$bitsAnyClear

Find(p => (p.PermissionFlags & 7) != 7);
{ PermissionFlags: { $bitsAnyClear: 7 } }

$bitsAnySet

Find(p => (p.PermissionFlags & 7) != 0);
{ PermissionFlags: { $bitsAnySet: 7 } }

Logical

See the MongoDB documentation for more information on each operator.

$or

Find(p => p.Name == "Jack" || p.Age == 10);
{ $or: [{ Name: 'Jack' }, { Age: 10 }] }

$and

Find(p => p.Name == "Jack" && p.Age < 40);
{ Name: 'Jack', Age: { $lt: 40 } }

Find(p => p.Age > 30 && p.Age < 40);
{ Age: { $gt: 30, $lt: 40 }

Find(p => p.Name != "Jack" && p.Name != "Jim");
{ $and: [{ Name: { $ne: 'Jack' } }, { Name: { $ne: 'Jim' } }] }

$not

Find(p => !(p.Age < 18))
{ Age: { $not: { $lt: 18 } } }

$nor

Find(p => !(p.Age < 18 || p.Age >= 65))
{ $nor: [{ Age: { $lt: 18 } }, { Age: { $gte: 65 } }] }

Element

See the MongoDB documentation for more information on each operator.

$exists

Find(p => p.Children.ContainsKey("John"))
{ "Children.John": { $exists: true } }

$type

Find(Builders<Person>.Filter.Type(p => p.Name, BsonType.String))
{ "Name" : { "$type" : 2 } }

Evaluation

See the MongoDB documentation for more information on each operator.

$mod

Find(p => p.Age % 2 == 0)
{ Age: { $mod: [NumberLong(2), NumberLong(0)] } }

$regex


Find(p => p.Name[0] == 'a')
{ Name: /^.{0}a/s }

Find(p => p.Name.Length >= 5)
{ Name: /^.{5,}$/s }

Find(p => p.Name.ToLower() == "john")
{ Name: /^john$/i }

Note
ToLowerInvariant, ToUpper, and ToUpperInvariant are also supported.


Find(p => p.Name.Contains("John"))
{ Name: /John/s }

Note
StartsWith and EndsWith are also supported.


Find(p => p.Name.ToLower().Contains("John"))
{ Name: /John/is }

Note
ToLowerInvariant, ToUpper, ToUpperInvariant, Trim, TrimStart, and TrimEnd are also supported for the first function call. StartsWith and EndsWith are also supported for the second function call.

$text

// no example yet

$where

// no example yet

Geospatial

See the MongoDB documentation for more information on each operator.

$geoWithin

// no example yet

$geoIntersects

// no example yet

$near

// no example yet

$nearSphere

// no example yet

Array

See the MongoDB documentation for more information on each operator.

$all

var local = new [] { 10, 20 };
Find(x => local.All(i => FavoriteNumbers.Contains(i));
{ FavoriteNumbers: { $all: [10, 20] } }

$elemMatch

Find(x => x.Pets.Any(p => p.Name == "Fluffy" && p.Age > 21);
{ Pets: { $elemMatch: { Name: 'Fluffy', Age: { $gt: 21 } } } }

Find(x => x.FavoriteNumbers.Any(n => n < 42 && n > 21));
{ FavoriteNumbers: { $elemMatch: { $lt: 42, $gt: 21 } } }

Note

Depending on the complexity and the operators involved in the Any method call, the driver might eliminate the $elemMatch completely. For instance,

Find(x => x.Pets.Any(p => p.Name == "Fluffy"))
{ Pets: { Name: "Fluffy" } }

$size

Find(x => x.FavoriteNumbers.Length == 3);
{ FavoriteNumbers: { $size: 3 } }

Find(x => x.FavoriteNumbers.Length != 3);
{ FavoriteNumbers: { $not: { $size: 3 } } }

Find(x => x.FavoriteNumbers.Any());
{ FavoriteNumbers: { $ne: null, $not: { $size: 0 } } }

Find(x => x.FavoriteNumbers.Count() == 3);
{ FavoriteNumbers: { $size: 3 } }

Aggregation Projections

We’ll walk through the supported expressions below. The tests are also a good reference.

Boolean Expressions

See the MongoDB documentation for more information on each operator.

$and

p => p.Name == "Jack" && p.Age < 40
{ $and: [{ $eq: ['$Name', 'Jack'] }, { $lt: ['$Age', 40] }] }

$or

p => p.Name == "Jack" || p.Age < 40
{ $or: [{ $eq: ['$Name', 'Jack'] }, { $lt: ['$Age', 40] }] }

$not

p => !(p.Name == "Jack")
{ $not: [{ $eq: ['$Name', 'Jack'] }]] }

Set Expressions

See the MongoDB documentation for more information on each operator.

$setEquals

p => p.FavoriteNames.SetEquals(new [] { "Jack", "Jane" });
{ $setEquals: ['$FavoriteNames', [ 'Jack', 'Jane'] ] }

var localSet = new HashSet<int>(new [] { 1, 3, 5 });

p => localSet.SetEquals(p.FavoriteNumbers);
{ $setEquals: [ [1, 3, 5], '$FavoriteNumbers' ] }

$setIntersection

p => p.FavoriteNumbers.Intersect(new [] { 1, 3 });
{ $setIntersection: [ '$FavoriteNumbers', [ 1, 3 ] ] }

p => new [] { 1, 3 }.Intersect(p.FavoriteNumbers);
{ $setIntersection: [ [ 1, 3 ], '$FavoriteNumbers' ] }

$setUnion

p => p.FavoriteNumbers.Union(new [] { 1, 3 });
{ $setUnion: [ '$FavoriteNumbers', [ 1, 3 ] ] }

p => new [] { 1, 3 }.Union(p.FavoriteNumbers);
{ $setUnion: [ [ 1, 3 ], '$FavoriteNumbers' ] }

$setDifference

p => p.FavoriteNumbers.Except(new [] { 1, 3 });
{ $setDifference: [ '$FavoriteNumbers', [ 1, 3 ] ] }

p => new [] { 1, 3 }.Except(p.FavoriteNumbers);
{ $setDifference: [ [ 1, 3 ], '$FavoriteNumbers' ] }

$setIsSubset

p => p.FavoriteNames.IsSubsetOf(new [] { "Jack", "Jane" });
{ $setIsSubset: ['$FavoriteNames', [ 'Jack', 'Jane'] ] }

var localSet = new HashSet<int>(new [] { 1, 3, 5 });

p => localSet.IsSubsetOf(p.FavoriteNumbers);
{ $setIsSubset: [ [1, 3, 5], '$FavoriteNumbers' ] }

$anyElementTrue

p => p.FavoriteNumbers.Any(x => x > 20);
{ $anyElementTrue: { $map: { input: '$FavoriteNumbers', as: 'x', in: { $gt: [ '$$x', 20 ] } } } }

$allElementsTrue

p => p.FavoriteNumbers.All(x => x > 20);
{ $allElementsTrue: { $map: { input: '$FavoriteNumbers', as: 'x', in: { $gt: [ '$$x', 20 ] } } } }

Comparison Expressions

See the MongoDB documentation for more information on each operator.

$cmp

p => p.Name.CompareTo("Jimmy");
{ $cmp: [ '$Name', 'Jimmy' ] }

$eq

p => p.Name == "Jimmy";
{ $eq: [ '$Name', 'Jimmy' ] }

$gt

p => p.Age > 20;
{ $gt: [ '$Age', 20 ] }

$gte

p => p.Age >= 20;
{ $gte: [ '$Age', 20 ] }

$lt

p => p.Age < 20;
{ $lt: [ '$Age', 20 ] }

$lte

p => p.Age <= 20;
{ $lte: [ '$Age', 20 ] }

$ne

p => p.Age != 20;
{ $ne: [ '$Age', 20 ] }

Arithmetic Expressions

See the MongoDB documentation for more information on each operator.

$abs

p => Math.Abs(p.Age);
{ $abs: "$Age" }

$add

p => p.Age + 2;
{ $add: [ '$Age', 2 ] }

$ceil

p => Math.Ceiling(p.Age);
{ $ceil: "$Age" }

$divide

p => p.Age / 2;
{ $divide: [ '$Age', 2 ] }

$exp

p => Math.Exp(p.Age);
{ $exp: ["$Age"] }

$floor

p => Math.Floor(p.Age);
{ $floor: "$Age" }

$ln

p => Math.Log(p.Age);
{ $ln: ["$Age"] }

$log

p => Math.Log(p.Age, 10);
{ $log: ["$Age", 10] }

$log10

p => Math.Log10(p.Age);
{ $log10: ["$Age"] }

$mod

p => p.Age % 2;
{ $mod: [ '$Age', 2 ] }

$multiply

p => p.Age * 2;
{ $multiply: [ '$Age', 2 ] }

$pow

p => Math.Pow(p.Age, 10);
{ $pow: ["$Age", 10] }

$sqrt

p => Math.Sqrt(p.Age);
{ $sqrt: ["$Age"] }

$subtract

p => p.Age - 2;
{ $subtract: [ '$Age', 2 ] }

$trunc

p => Math.Truncate(p.Age);
{ $trunc: "$Age" }

String Expressions

See the MongoDB documentation for more information on each operator.

$concat

p => p.Name + "Awesome";
{ $concat: [ '$Name', 'Awesome' ] }

$substr

p => p.Name.Substring(3, 20)
{ $substr: [ '$Name', 3, 20 ] }

$toLower

p => p.Name.ToLower()
{ $toLower: '$Name' }

$toUpper

p => p.Name.ToUpper()
{ $toUpper: '$Name' }

$strcasecmp

You must use StringComparison.OrdinalIgnoreCase for this method.

p => p.Name.Equals("balloon", StringComparison.OrdinalIgnoreCase);
{ $strcasecmp: ['$Name', 'balloon' ] }

Text Search Expressions

See the MongoDB documentation for more information on each operator.

$meta

// no example yet

Array Expressions

See the MongoDB documentation for more information on each operator.

$arrayElemAt

p => p.FavoriteNumbers.First()
{ $arrayElemAt: ['$FavoriteNumbers', 0] }
p => p.FavoriteNumbers.Last()
{ $arrayElemAt: ['$FavoriteNumbers', -1] }

$avg

p => p.FavoriteNumbers.Average()
{ $avg: '$FavoriteNumbers' }

$concatArrays

p => p.FavoriteNumbers.Concat(new [] { 1, 2, 3 })
{ $concatArrays: ['$FavoriteNumbers', [1, 2, 3]] }

$filter

p => p.FavoriteNumbers.Where(x => x > 10)
{ $filter: { input: '$FavoriteNumbers', as: 'x', cond: { $gt: ['$$x', 10] } } }

$map

p => p.FavoriteNumbers.Select(x => x + 10)
{ $map: { input: '$FavoriteNumbers', as: 'x', in: { $add: ['$$x', 10] } } }

$max

p => p.FavoriteNumbers.Max()
{ $max: '$FavoriteNumbers' }

$min

p => p.FavoriteNumbers.Min()
{ $min: '$FavoriteNumbers' }

$size

p => p.FavoriteNumbers.Length;
{ $size: '$FavoriteNumbers' }

p => p.FavoriteNumbers.Count();
{ $size: '$FavoriteNumbers' }

$slice

p => p.FavoriteNumbers.Take(2)
{ $slice: ['$FavoriteNumbers', 2] }
p => p.FavoriteNumbers.Skip(3).Take(2)
{ $slice: ['$FavoriteNumbers', 3, 2] }

$stdDevPop

p => p.FavoriteNumbers.StandardDeviationPopulation()
{ $stdDevPop: '$FavoriteNumbers' }

$stdDevSamp

p => p.FavoriteNumbers.StandardDeviationSample()
{ $stdDevPop: '$FavoriteNumbers' }

$sum

p => p.FavoriteNumbers.Sum()
{ $sum: '$FavoriteNumbers' }

Variable Expressions

See the MongoDB documentation for more information on each operator.

$map

p => p.Pets.Select(x => x.Name + " is awesome");
{ $map: { input: '$Name', as: 'x', in: { $concat: [ '$$x', ' is awesome' ] } } }

$let

// no example yet

Literal Expressions

See the MongoDB documentation for more information on each operator.

$literal

The only time $literal will be used from the driver is if the constant starts with a $.

p => p.Name == "$1");
{ $eq: [ '$Name', { $literal: '$1' } ] }

Date Expressions

See the MongoDB documentation for more information on each operator.

$dayOfYear

p => p.CreatedAtUtc.DayOfYear);
{ $dayOfYear: '$CreatedAtUtc' }

$dayOfMonth

p => p.CreatedAtUtc.Day);
{ $dayOfMonth: '$CreatedAtUtc' }

$dayOfWeek

The .NET constant for day of week is 1 less than that in MongoDB. As such, we must subtract 1 from the MongoDB version in order for mapping back to the .NET type to be accurate.

p => p.CreatedAtUtc.DayOfWeek;
{ $subtract: [ { $dayOfWeek: '$CreatedAtUtc' }, 1 ] }

$year

p => p.CreatedAtUtc.Year;
{ $year: '$CreatedAtUtc' }

$month

p => p.CreatedAtUtc.Month;
{ $month: '$CreatedAtUtc' }

$week

// no example yet

$hour

p => p.CreatedAtUtc.Hour;
{ $hour: '$CreatedAtUtc' }

$minute

p => p.CreatedAtUtc.Minute;
{ $minute: '$CreatedAtUtc' }

$second

p => p.CreatedAtUtc.Second;
{ $second: '$CreatedAtUtc' }

$millisecond

p => p.CreatedAtUtc.Millisecond;
{ $millisecond: '$CreatedAtUtc' }

$dateToString

// no example yet

Conditional Expressions

See the MongoDB documentation for more information on each operator.

$cond

p => p.Name == "Jack" ? "a" : "b";
{ $cond: [ { $eq: [ '$Name', 'Jack' ] }, 'a', 'b' ] }

$ifNull

p => p.Name ?? "awesome";
{ $ifNull: [ '$Name', 'awesome' ] }

Accumulators

See the MongoDB documentation for more information on each operator.

Also, the tests are a good reference.

Note
These are only supported in a grouping expression.

In the examples below, it should be assumed that g is of type IGrouping<TKey, TElement>.

$sum

g => g.Sum(x => x.Age);
{ $sum: '$Age' }

g => g.Count()
{ $sum: 1 }

$avg

g => g.Average(x => x.Age);
{ $avg: '$Age' }

$first

g => g.First().Age);
{ $first: '$Age' }

$last

g => g.Last().Age);
{ $last: '$Age' }

$max

g => g.Max(x => x.Age);
{ $max: '$Age' }

$min

g => g.Min(x => x.Age);
{ $min: '$Age' }

$push

g => g.Select(p => p.Name)
{ $push: '$Name' }

g => g.Select(p => p.Name).ToArray()
{ $push: '$Name' }

g => g.Select(p => p.Name).ToList()
{ $push: '$Name' }

$addToSet

g => new HashSet<string>(g.Select(p => p.Name));
{ $addToSet: '$Name' }

g => g.Select(p => p.Name).Distinct();
{ $addToSet: '$Name' }