Mongo C# Fluent 聚合管道组匿名类型键异常
Mongo C# Fluent Aggregation Pipeline Group Anonymous Type Key Exception
我在 10gen Mongo C# 驱动程序的 v2 中使用新的 Fluent 聚合管道,但在尝试按多个字段分组时遇到异常(下面的示例代码)。
抛出的异常是...
命令聚合失败:异常:组聚合字段'Month'必须定义为对象内部的表达式。
我可以通过为我的组密钥创建一个类型来实现它,但我更愿意使用匿名类型,因为我需要创建的类型不会用于其他目的。
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;
供参考...
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; }
}
fluent API生成的命令是...
{ "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" : { } }
问题是您引用的字段没有对其执行聚合。所有不属于 _id 的字段都需要聚合。您会注意到 Month 和 Product 已经是 _id 的一部分,因此无需在分组语句中再次请求它们。我建议改为这样做:
var group = project.Group(
key => new { key.Month, key.Product },
g => new
{
MonthAndProduct = g.Key,
TotalSales = g.Sum(o => o.Value)
});
如果您之后需要将其展平,您可以将上面的内容更改为 return 匿名类型,然后在客户端或与另一个 $project 进行投影。
var project = group.Project(x => new OrderSummary
{
Month = x.MonthAndProduct.Month,
Product = x.MonthAndProduct.Product,
TotalSales = x.TotalSales
});
如果您仍然觉得这是驱动程序中的错误,请在 CSHARP 项目下的 jira.mongodb.org 提交 bug/feature 请求票。
谢谢,
克雷格
我在 10gen Mongo C# 驱动程序的 v2 中使用新的 Fluent 聚合管道,但在尝试按多个字段分组时遇到异常(下面的示例代码)。
抛出的异常是...
命令聚合失败:异常:组聚合字段'Month'必须定义为对象内部的表达式。
我可以通过为我的组密钥创建一个类型来实现它,但我更愿意使用匿名类型,因为我需要创建的类型不会用于其他目的。
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;
供参考...
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; }
}
fluent API生成的命令是...
{ "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" : { } }
问题是您引用的字段没有对其执行聚合。所有不属于 _id 的字段都需要聚合。您会注意到 Month 和 Product 已经是 _id 的一部分,因此无需在分组语句中再次请求它们。我建议改为这样做:
var group = project.Group(
key => new { key.Month, key.Product },
g => new
{
MonthAndProduct = g.Key,
TotalSales = g.Sum(o => o.Value)
});
如果您之后需要将其展平,您可以将上面的内容更改为 return 匿名类型,然后在客户端或与另一个 $project 进行投影。
var project = group.Project(x => new OrderSummary
{
Month = x.MonthAndProduct.Month,
Product = x.MonthAndProduct.Product,
TotalSales = x.TotalSales
});
如果您仍然觉得这是驱动程序中的错误,请在 CSHARP 项目下的 jira.mongodb.org 提交 bug/feature 请求票。
谢谢, 克雷格