尝试按对象分组作为键时,字段必须是累加器对象错误

Mat*_*ias 1 c# mongodb aggregation-framework .net-core mongodb-.net-driver

我正在尝试按集合中的多个属性对文档进行类型安全的分组。我发现问题不在于按多个属性本身进行分组,而是键是对象 ( new { }) 而不是字符串。

这有效:

collection.Aggregate().Group(x => x.Name, x => new { Name = x.Key, Count = x.Sum(s => 1) }).ToList();
Run Code Online (Sandbox Code Playgroud)

这不起作用:

collection.Aggregate().Group(x => new { Name = x.Name }, x => new { Name = x.Key.Name, Count = x.Sum(s => 1) }).ToList();
Run Code Online (Sandbox Code Playgroud)

错误是:

MongoDB.Driver.MongoCommandException:“命令聚合失败:字段“名称”必须是累加器对象。

当我将不起作用的查询转换为字符串时,我得到以下信息:

aggregate([{ "$group" : { "_id" : { "Name" : "$Name" }, "Name" : "$_id.Name", "Count" : { "$sum" : 1 } } }])
Run Code Online (Sandbox Code Playgroud)

我想这里的问题是这部分"Name" : "$_id.Name"。我该如何解决这个问题?

我目前使用的是 2.8.0 版的 mongodb 驱动程序。

mic*_*ckl 6

实际上驱动程序在这里行为正确,但您遇到的是聚合框架中$group管道阶段的限制。该文件指出:

输出文档包含一个 _id 字段,其中包含不同的 group by key。输出文档还可以包含计算字段,这些字段保存按 $group 的 _id 字段分组的某些累加器表达式的值

因此,在您的情况下,您试图在_id没有任何累加器的情况下引用字段。

从逻辑的角度来看,您的查询似乎是相似的。第一个被翻译成:

{
    "$group" : {
        "_id" : "$Name",
        "Count" : {
            "$sum" : 1
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第二个将返回相同的数据,但您有一个对象作为分组键。要在 C# 中解决这个问题,您需要引入.First()将被转换为$first 的表达式,因此运行:

Col.Aggregate()
    .Group(
        x => new { Name = x.Name }, 
        x => new { Name = x.First().Name, Count = x.Sum(s => 1) })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

将在数据库上运行以下查询:

{
    "$group" : {
        "_id" : {
            "Name" : "$Name"
        },
        "Name" : {
            "$first" : "$Name"
        },
        "Count" : {
            "$sum" : 1
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它可以工作,但在逻辑上它返回与第一次聚合相同的数据