在 MongoDB 的聚合管道中获取 $group 之后的输入文档中的字段
Posted
技术标签:
【中文标题】在 MongoDB 的聚合管道中获取 $group 之后的输入文档中的字段【英文标题】:get the fields in the input document after $group in aggregation pipeline in MongoDB 【发布时间】:2015-05-12 19:24:55 【问题描述】:我面临的问题是如何在一次分组操作后访问原始文档,以及如何在MongoDB的聚合管道中携带$group之后的字段。
例如:[group, unwind, group]
原始文件是:
"_id" : ObjectId("361de42f1938e89b179dda42"),
"user_id" : ObjectId("9424021bafbde55512e39b83"),
"candidate_id" : ObjectId("54f65356294160421ead3ca1")
"OVERALL_SCORE" : 150,
"SCORES" : [
"NAME" : "asd", "OBTAINED_SCORE" : 28, "NAME" : "acd", "OBTAINED_SCORE" : 36 , "NAME" : "abc", "OBTAINED_SCORE" : 40
]
聚合函数:
db.coll.aggregate([ $group : _id : user_id : "$user_id", BEST_SCORE : $max : "$OVERALL_SCORE", AVG_SCORE : $avg : "$OVERALL_SCORE" ])
以下是示例输出(第一组之后):
"result" : [
"_id" :
"user_id" : ObjectId("9424021bafbde55512e39b83")
,
"BEST_SCORE" : 150,
"AVG_SCORE" : 132
],
"ok" : 1
问题是:(不知道能不能实现) 我想要原始文档中的字段(聚合的输入)。
例如: 1) 通过“candidate_id”、“user_id”展开原始文档和下一组中的“SCORES”。
2) 我希望“BEST_SCORE”、“AVG_SCORE”(在第一组之后)字段也可以在第二组中访问。
聚合函数应该是这样的:
db.coll.aggregate([ $group : _id : user_id : "$user_id", BEST_SCORE : $max : "$OVERALL_SCORE", AVG_SCORE : $avg : "$OVERALL_SCORE" , $unwind : "$SCORES", /*problem is--after group operation "SCORES" field which is in original document not available */ $group : _id : NAME: "$SCORES.NAME", AVG_OBTAINED_SCORE: $avg : "$SCORES.OBTAINED_SCORE" **/*problem is--this is also in the original document*/** ])
输出应如下所示:
"BEST_SCORE": 150, //after 1st group
"AVG_SCORE": 132, //after 1st group
"SCORES": [ //problem --- unwind "SCORES" and then group which is actually will not be available after 1st group (get this from original document)
"NAME": "abc",
"AVG_OBTAINED_SCORE": 25.5
,
"NAME": "asd",
"AVG_OBTAINED_SCORE": 24
,
"NAME": "acd",
"AVG_OBTAINED_SCORE": 32
]
谁能帮帮我。
谢谢
【问题讨论】:
这并没有多大意义。您只能真正“保留”“分组键”中的内容,否则可以由分组运算符之一保留,就像您使用其他值或可选的 $last 或 $push 之类的东西一样。保留其他字段的意义何在?您对最终结果的期望是什么。$$ROOT
仅指调用它的聚合阶段的“整个文档”。因此,一旦您在一个阶段更改了文档,那么$$ROOT
的值就是在另一个阶段访问时更改的形式。您无法看到文档在进行其他更改之前的样子。正如我之前建议的那样,您的预期结果并不是很清楚。如果您编辑您的问题以显示您的期望,那么人们可能会就实现目标的方法提出建议。
我已经编辑了..希望现在更清楚..
你在 "name": "asd"
应该来自的地方失去了我们。除非它是“SCORES”数组文档的一部分,否则你很可能在这里不走运。它真的是那些数组文档中的一个元素吗?
我们不要聊天。这是一个是或不是的答案。否则,请更改您问题的详细信息以解释数据应该来自哪里
【参考方案1】:
当与您希望保留组中所有考虑文档的值的内容进行分组时,您需要使用$push
。抓住的是,这是一个数组。所以你处理$unwind
两次,并且还有两个$group
阶段:
db.coll.aggregate([
"$group" :
"_id": "$user_id",
"BEST_SCORE": "$max": "$OVERALL_SCORE" ,
"AVG_SCORE": "$avg": "$OVERALL_SCORE" ,
"SCORES": "$push": "SCORES"
,
// SCORES in an array of arrays. Unwind twice
"$unwind": "$SCORES" ,
"$unwind": "$SCORES" ,
// Group for averages on elements
"$group":
"_id":
"user_id": "$_id",
"NAME": "$SCORES.name"
,
"BEST_SCORE": "$first": "$BEST_SCORE" ,
"AVG_SCORE": "$first": "$AVG_SCORE"
"AVG_OBTAINED_SCORE": "$avg": "$SCORES.OBTAINED_SCORE"
,
// Group to user_id
"$group":
"user_id": "$_id.user_id",
"BEST_SCORE": "$first": "$BEST_SCORE" ,
"AVG_SCORE": "$first": "$AVG_SCORE"
"SCORES": "$push":
"NAME": "$_id.NAME",
"AVG_OBTAINED_SCORE": "$AVG_OBTAINED_SCORE"
])
您可能想在第一个 $group
之前考虑使用 $unwind
,但如果您这样做了,那么计算的平均值将受到正在“解绕”的数组中存在的元素数量的影响。所以这里的“双重$unwind”是一个必要的过程。
【讨论】:
如果有任何字段要结转到下一个管道操作员,我们需要使用$push或$addToSet。 @user3805045 你需要做一些事情,但这些都适合这个用例。 $push 和 $addToSet 之间的主要区别在于 push 添加的元素保持其顺序(无论在前面的阶段是什么),而 $addToSet 则以无特定顺序添加元素:docs.mongodb.com/manual/reference/operator/aggregation/addToSet以上是关于在 MongoDB 的聚合管道中获取 $group 之后的输入文档中的字段的主要内容,如果未能解决你的问题,请参考以下文章