Introduction to MongoDb with .NET part 28: aggregation in the .NET driver using loose typing and AppendStage
May 17, 2016 1 Comment
Introduction
In the previous post we started looking into MongoDb aggregations via the .NET driver. Our first example was a single $sort stage using the AppendStage function. The AppendStage function is generic in the sense that it can accept just any type of aggregation stage to be added to the pipeline. We also introduced the BsonDocument object which offers a way to describe MongoDb documents in a loosely typed way.
In this post we’ll continue our discussion and build the pipeline we’re targeting.
More stages with AppendStage
Recall how we added the $sort stage using AppendStage and BsonDocument:
ModelContext modelContext = ModelContext.Create(new ConfigFileConfigurationRepository(), new AppConfigConnectionStringRepository()); var res = modelContext.ZipCodes.Aggregate() .AppendStage<BsonDocument>(new BsonDocument { { "$sort", new BsonDocument("_id", 1) } }).ToList();
Let’s continue along those lines. For a reminder here’s what we’re trying to achieve:
db.zipcodes.aggregate([ {$group: { "_id" : "$state", "population" : {$sum : "$pop"}}}, {$match : {population : {$gte : 5000000}}}, {$sort: {"_id" : 1}}, {$limit : 5}])
The group stage JSON document can be constructed as follows using the BsonDocument object:
BsonDocument groupStageBson = new BsonDocument { { "$group", new BsonDocument("_id", "$state") .Add("population", new BsonDocument("$sum", "$pop")) } };
This is equivalent to…
{ "$group" : { "_id" : "$state", "population" : { "$sum" : "$pop" } } }
The matching stage can be expressed as follows:
BsonDocument matchStageBson = new BsonDocument { { "$match", new BsonDocument("population", new BsonDocument("$gte", 5000000)) } };
We’ve already seen the BsonDocument equivalent of the sort stage. The limit stage is an easy one so I’ll just present the final query using AppendStage only:
List<BsonDocument> looselyTypedAggregation = modelContext.ZipCodes.Aggregate() .AppendStage<BsonDocument> ( new BsonDocument { { "$group", new BsonDocument("_id", "$state") .Add("population", new BsonDocument("$sum", "$pop")) } } ) .AppendStage<BsonDocument> ( new BsonDocument { { "$match", new BsonDocument("population", new BsonDocument("$gte", 5000000)) } } ) .AppendStage<BsonDocument> ( new BsonDocument { { "$sort", new BsonDocument("_id", 1) } } ) .AppendStage<BsonDocument> ( new BsonDocument("$limit", 5) ) .ToList(); foreach (var item in looselyTypedAggregation) { var nameList = item.Names.ToList(); foreach (string name in nameList) { BsonValue bsonValue = item.GetValue(name); Console.WriteLine(string.Format("{0}: {1}", name, bsonValue)); } }
Here’s the output of the above snippet:
_id: CA
population: 29754890
_id: FL
population: 12686644
_id: GA
population: 6478216
_id: IL
population: 11427576
_id: IN
population: 5544136
…which is the same as the expected set of documents we saw in the previous post:
{ "_id" : "CA", "population" : 29754890 } { "_id" : "FL", "population" : 12686644 } { "_id" : "GA", "population" : 6478216 } { "_id" : "IL", "population" : 11427576 } { "_id" : "IN", "population" : 5544136 }
We’ve seen one alternative to write the aggregation in the .NET writer. It’s very loosely typed with strings and BsonDocuments and is not much different from writing actual JSON code.
In the next post we’ll look at a more strongly typed solution using the dedicated aggregation methods of the aggregation fluent API.
You can view all posts related to data storage on this blog here.
There seems to be one category of aggregations that is not covered (not in your post or others that I could find).
Specifically, I need to run queries entered by the user at run-time. It means I can’t write the query in pre-compiled C# code.
Below is a simple example of a query entered at run time by the user. How do I convert this pipeline into c# at run-time?
-Thanks in advance
David
— — — —
[
{
$match:
{
talentId:
{
$in: [‘9wpeWRqq1Ag’,’FAvWm7Gn1Ag’,’56N98Ocd1Qg’]
}
}
},
{
$match:
{
$or:
[
{
$and:
[
{ /c#/i },
{ /java/i }
]
},
{
$and:
[
{ /python/i },
{ /lisp/i }
]
}
]
}
},
{
$project:
{
_id: 0,
talentId: 1
}
}
]