Introduction to MongoDb with .NET part 28: aggregation in the .NET driver using loose typing and AppendStage


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:

{$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()
		new BsonDocument { { "$group", new BsonDocument("_id", "$state")
			.Add("population", new BsonDocument("$sum", "$pop")) } }
		new BsonDocument { { "$match", new BsonDocument("population", new BsonDocument("$gte", 5000000)) } }
		new BsonDocument { { "$sort", new BsonDocument("_id", 1) } }
		new BsonDocument("$limit", 5)
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.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

One Response to Introduction to MongoDb with .NET part 28: aggregation in the .NET driver using loose typing and AppendStage

  1. david marcus says:

    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

    — — — —

    $in: [‘9wpeWRqq1Ag’,’FAvWm7Gn1Ag’,’56N98Ocd1Qg’]

    { /c#/i },
    { /java/i }
    { /python/i },
    { /lisp/i }

    _id: 0,
    talentId: 1

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s


A great site

Elliot Balynn's Blog

A directory of wonderful thoughts

HarsH ReaLiTy

A Good Blog is Hard to Find

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog


Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: