πŸ“¦Group

Group documents

The group stage groups documents by a specified _id expression and outputs a document for each group. One way to use the Match stage in a pipeline is to use the Aggregate method in a IMongoCollection<T> and chain the Group method.

IMongoCollection<T>.Aggregate()
    .Group(doc => doc.<field>, <output>)

The sample groups User documents by their profession field and outputs the total documents per group.

Group.cs
var collection = database.GetCollection<User>(collectionName);

var singleFieldAggregate = collection.Aggregate()
    .Group(u => u.Profession,
        ac => new { 
            profession = ac.Key, 
            total = ac.Sum(u => 1)
        });

var groupedProfessions = 
    await singleFieldAggregate.ToListAsync();
    
foreach (var group in groupedProfessions)
{
    Utils.Log($"{group.profession}: {group.total}");
}

Group by an embedded document's field

You can group by any document's field you want. The sample groups the User documents by the Address.State field to find the total documents per state sorted by total.

Group.cs
var collection = database.GetCollection<User>(collectionName);

var embeddedDocFieldAggregate = collection.Aggregate()
    .Group(u => u.Address.State, // embedded document
        ac => new {state = ac.Key, total = ac.Sum(u => 1)})
    .SortBy(group => group.total); // ASC

var groupedPerCountry = await embeddedDocFieldAggregate
    .ToListAsync();

Match - Group - Project

The sample combines 4 stages to calculate the average monthly expenses per gender.

  • The $match stage filters documents based on the salary

  • The $group stage groups the filtered documents per gender and calculate the average monthly expenses

  • The $project stage formats the gender as a string

  • The last stage $sort, simply sorts the results per average monthly expenses

var collection = database.GetCollection<User>(collectionName);

var excercice1Aggregate = collection.Aggregate()
    .Match(Builders<User>.Filter.Gte(u => u.Salary, 1500) &
           Builders<User>.Filter.Lte(u => u.Salary, 3000))
    .Group(u => u.Gender,
        ac => new
        {
            gender = ac.Key,
            averageMonthlyExpenses = ac.Average(u => u.MonthlyExpenses),
            total = ac.Sum(u => 1)
        })
    .Project(group => new 
    {
        Gender = group.gender == 0 ? "Male" : "Female",
        AverageMonthlyExpenses = group.averageMonthlyExpenses,
        Total = group.total
    })
    .SortByDescending(group => group.AverageMonthlyExpenses);
    
var excercice1Result = await excercice1Aggregate.ToListAsync();

The LINQ query supports the Math.Ceiling method and can produce an average of Int32 type.

Last updated