I am using the new Fluent Aggregation Pipeline in v2 of the 10gen Mongo C# driver, but am experiencing an exception when trying to group by more than one field (example code below).
The Exception that is thrown is ...
Command aggregate failed: exception: the group aggregate field 'Month' must be defined as an expression inside an object.
I can get this to work by creating a type for my group key but would prefer to use an anonymous type as the type i will need to create will serve no other purpose.
var agg = db.GetCollection<Order>("orders").Aggregate();
var project = agg.Project(o => new {o.Value
, o.Product
, Month = o.Date.Month
, Year = o.Date.Year});
var group = project.Group(
key => new { key.Month, key.Product},
g => new OrderSummary {Month = g.Key.Month
,Product = g.Key.Product
, TotalSales = g.Sum(o => o.Value)});
var result = group.ToListAsync().Result;
For reference ...
public class Order : Entity
{
public DateTime Date { get; set; }
public string Product { get; set; }
public double Value { get; set; }
}
public class OrderSummary
{
public string Product { get; set; }
public int Month { get; set; }
public int Year { get; set; }
public double TotalSales { get; set; }
}
The command generated by the fluent API is ...
{ "aggregate" : "Order",
"pipeline" : [
{ "$project" : { "Value" : "$Value", "Product" : "$Product", "Month" : { "$month" : "$Date" }, "Year" : { "$year" : "$Date" }, "_id" : 0 } }
, { "$group" : {
"_id" : { "Month" : "$Month", "Product" : "$Product" }
, "Month" : "$Month"
, "Product" : "$Product"
, "TotalSales" : { "$sum" : "$Value" } } }]
, "cursor" : { } }
The problem is that you are referring to a field without performing an aggregation on it. All fields that aren't a part of the _id need to be aggregated. You'll notice that Month and Product are already part of the _id, so there is no need to ask for them again in the grouping statement. I'd suggest doing this instead:
var group = project.Group(
key => new { key.Month, key.Product },
g => new
{
MonthAndProduct = g.Key,
TotalSales = g.Sum(o => o.Value)
});
If you need to flatten this out afterwards, you can change the above to return an anonymous type and then either do projecting client-side or with another $project.
var project = group.Project(x => new OrderSummary
{
Month = x.MonthAndProduct.Month,
Product = x.MonthAndProduct.Product,
TotalSales = x.TotalSales
});
If you still feel this is a bug in the driver, please file a bug/feature request ticket at jira.mongodb.org under the CSHARP project.
Thanks, Craig
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With