我正在学习 MongoDB 并尝试对集合进行分组。 我正在寻找的是按年份分组,获取最大“平均注释”字段并显示与此平均值相关的文档的字段主名称
例如,如果我有:
Name | Average | Year
Name_01 | 7.56 | 1995
Name_02 | 8.96 | 1995
Name_03 | 3.25 | 2005
Name_04 | 4.36 | 2005
Name_05 | 7.52 | 2020
我需要:
Name | Average | Year
Name_02 | 8.96 | 1995
Name_05 | 7.52 | 2020
Name_04 | 4.36 | 2005
我已经完成了小组和最大值。这是我的代码:
db.foobar.aggregate([
{
$group: { _id: '$year_published', max: { $max: '$statistics.average' }}
},
{
$project: { _id: 1, max: 1 }
},
{
$sort: { max: -1 }
}
])
这给了我这样的结果:
{
"result" : [
{
"_id" : 1999,
"max" : 8.0343000000000000
},
{
"_id" : 1985,
"max" : 7.8833299999999999
}
// An so on...
}
但我还想投影与“max”相关的文档的主要名称,以获得如下内容:
{
"result" : [
{
"_id" : 1999,
"max" : 8.0343000000000000,
"name": "Foo Bar"
},
{
"_id" : 1985,
"max" : 7.8833299999999999,
"name": "Lorem Ipsum"
}
// An so on...
}
注意:问题的下一部分增加了名称的复杂性(因为我的文档结构)。这不是我现在主要关心的问题,但我将其添加到问题中以反射(reflect)我的所有问题。
主要名称有点难以获取。对于每个文档,我都有一个这样的对象数组:
{
"names" : [
{
"type" : "primary",
"value" : "Foo bar"
},
{
"type" : "alternate",
"value" : "Foo foo"
},
{
"type" : "alternate",
"value" : "Bar bar"
}
]
}
我想要获取的是“主要”类型的名称(即我的示例中的“Foo bar”)。
这是我的文档的结构:
{
"_id" : ObjectId("56338f2bdc99b8ec22a43328"),
"names" : [
{
"type" : "primary",
"value" : "Foo bar"
},
{
"type" : "alternate",
"value" : "Barr foo"
}
],
"year_published" : 1992
"statistics" : {
"average" : 6.6057699999999997
}
}
我想我还没有做到这一点,但我不知道该怎么做......你能帮我吗?
最佳答案
如果您希望特定文档中的“配对”值具有“最大值”,那么 $max
不适合您。相反,你需要做的是 $sort
先获取数据,然后使用 $first
运算符。
db.foobar.aggregate([
{ "$sort": { "year_published": 1, "statistics.average": -1 } },
{ "$group": {
"_id": "$year_published",
"max": { "$first": "$statistics.average" }},
"name": {
"$first": {
"$setDifference": [
{ "$map": {
"input": "$names",
"as": "name",
"in": {
"$cond": {
"if": { "$eq": [ "$$name.type", "primary" ] },
"then": "$$name.value",
"else": false
}
}
}},
[false]
]
}
}
}},
{ "$unwind": "$name" }
])
$first
和 $last
运算符作用于“分组边界”数据。这意味着它们从用于分组 _id
的值的开头或结尾处出现的属性返回数据。
这就是为什么您首先要“排序”,以便文档按顺序进行选择。
相比之下,$max
和 $min
只需从示例文档中的任意位置选取“max/min”值。如果这就是您想要的,那很好,但如果您想要“相关”字段,那么您必须首先排序。
这就是它的基础知识。处理数组过滤的另一部分最好使用 $map
来完成。和 $setDifference
组合如图所示。 $map
允许通过 $cond
测试条件对每个数组元素“内联”,并根据 true 或 false 返回值。结果当然仍然是一个等长的数组。
$setDifference
本质上会过滤掉任何返回为 false
的内容,因此唯一剩下的应该是“primary”。仍然是一个数组,这就是为什么仍然使用 $unwind
的原因,尽管它只是一个单元素数组。
future 的 MongoDB 版本将通过 $filter
和 $arrayElemAt
做得更好。下面是一瞥:
db.foobar.aggregate([
{ "$sort": { "year_published": 1, "statistics.average": -1 } },
{ "$group": {
"_id": "$year_published",
"max": { "$first": "$statistics.average" }},
"name": {
"$first": {
"$arrayElemAt": [
{ "$filter": {
"input": "$names",
"as": "name",
"cond": {
"$eq": [ "$$name.type", "primary" ]
}
}},
0
]
}
}
}}
])
但是这些都不会改变“先排序”的基本规则,然后从分组边界中选取值。
关于mongodb - 如何使用 MongoDB 从聚合结果中投影附加数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33495346/