-
Notifications
You must be signed in to change notification settings - Fork 227
Linq
Querying using linq will be most natural fit for .NET developers. It means that you won’t have to learn MongoDB’s query language unless you need some more advanced queries or fine tuning. For the best overview of the MongoDB query capabilities, you should reference the mongodb-docs.
There are 2 modes in which querying MongoDB can occur. Our linq provider will make the choice for you based on certain criteria.
Native mode will be used when your query only uses the supported (native) MongoDB operators. It allows MongoDB to make the best use of indexes so that your query performs well. As MongoDB supports more operators, we will also support them as well.
An example Native Mode query is below (using Typed Collections)
var people = from p in collection.Linq()
where p.Age >= 18 && p.FirstName.StartsWith("J")
orderby p.FirstName
select p.FirstName + " " + p.LastName;
It is very easy to push a query into Javascript Mode. Simply using a disjunction (or) would do the trick. MongoDB can make limited use of the indexes when Javascript Mode is used which results in “table” scans to grab the correct data. However, there can be advantages to using this mode if your query is complex and performance is unnecessary. See the mongodb-docs for more information.
An example Javascript Mode query is below (using Typed Collections)
var people = from p in collection.Linq()
where p.FirstName.StartsWith("J") || p.LastName.StartsWith("J")
orderby p.FirstName
select p.FirstName + " " + p.LastName;
In addition to disjunctions, any legal Javascript is allowed in a Javascript query. Therefore, addition, subtraction, etc…, left shifts, right shifts, etc… are all supported making it very powerful.
Not all Linq operations are supported. Currently, there is not support for GroupBy or aggregate operations (other than Count). We will be filling these holes in due time.
Any combination of the supported operators are valid to remain in Native Mode. In addition, there are certain native .NET isms that are automatically translated into their appropriate MongoDB syntax.
x => x.Age == 21 will translate to {"Age": 21}
x => x.Age > 18 will translate to {"Age": {$gt: "Bob"}}
x => x.Age >= 18 will translate to {"Age": {$gte: "Bob"}}
x => x.Age < 18 will translate to {"Age": {$lt: "Bob"}}
x => x.Age <= 18 will translate to {"Age": {$lte: "Bob"}}
x => x.Age != 18 will translate to {"Age": {$ne: "Bob"}}
Not currently supported.
All regular expressions must be in accordance with the Javascript regular expression syntax. There are some similarities to the .NET syntax, but if you find a query misbehaving, it might be that the syntax is incorrect. In any case, below is how MongoDB-CSharp supports regular expressions in Linq queries.
This type of regex query will allow mongodb to use an index.
x => x.FirstName.StartsWith("J") will translate to {"FirstName": /^J/}
x => x.FirstName.Contains("oe") will translate to {"FirstName": /oe/}
x=> x.FirstName.EndsWith("oe") will translate to {"FirstName": /oe$/}
x => Regex.IsMatch("^J.*e$", x.FirstName) will translate to {"FirstName": /^J.*e$/}
Limited or support can be gained through the use of an $in clause. We support this through local collections.
var firstNames = new[] { "Joe", "Bob" };
var people = collection.Linq().Where(x => firstNames.Contains(x => x.FirstName));
This will translate to {"FirstName": {$in: [“Joe”, “Bob”]}}. Essentially, we are asking to find all the people whose FirstName is “Joe” or “Bob”.
Matching on embedded collections can be done through the use of the Any operator. It will translate into an $elemMatch query.
var people = collection.Linq().Where(x => x.Addresses.Any(a => a.City == "Paris"));
This will tranlate to {"Addresses": {$elemMatch: {"City": "Paris"}}}. Essentially, we are asking to find all the
people that have an address whose city is Paris.
Size is supported by using the Count() extension method, the Count property on an ICollection instance, or the Length property on an Array.
x => x.Addresses.Count() == 4) would translate to {"Addresses": {$size: 4}}
Note that $size queries only allow the use of equality and no other operators.
If you want to query the 4th element in a list, MongoDB has support for this. Either use an indexer off IList, an indexer off an array, or the ElementAt extension method.
x => x.Addresses[4].City == "Paris" will translate to{"Addresses.4.City": "Paris"}.
All operators are supported here.
MongoDB-CSharp supports projections as completely as MongoDB supports them. That is to say that we can pull back only the subset of fields that are requested. In addition to that, it is possible to perform some client side manipulation of the results.
...Linq().Select(x => x.FirstName + " " + x.LastName)
This will bring back only the FirstName and LastName fields from MongoDB and then concatenate them together client side, giving you a single string to work with.
A more complex example is below showing that derived fields will still perform correctly in the case where a linq query is composed in pieces. This example is a little trite, but it illustrates the point.
var people = from p in collection.Linq()
select new {Name = p.FirstName + " " + p.LastName, Age = p.Age};
//other code
var names = from p in people
where p.Age >= 21
select p.Name;
This query would result in a single query being issued to MongoDB for all people whose Age is greater than or equal to 21 and it would only pull back the FirstName and LastName fields. Client side, we’d stitch together the names, giving you a single string to work with.
Order by is supported, including direction. Simply specify the fields to order by and you are good to go.
var people = from p in collection.Linq()
orderby p.Age descending
select p;
The Count aggregate is supported natively utilizing MongoDB. All other aggregates require the use of Map-Reduce.
To use, simply use the Count linq operator as the last operator in the query. It is supported both with and without the predicate.
...Linq().Count(x => x.Age > 21)
Paging can be accomplished using the skip and take operators.
...Linq().Skip(10).Take(10)