我有一个要求,我需要对两个记录进行聚合,并且两个记录都有一个具有不同值的数组字段。我需要在这些记录上进行聚合时,结果应该有一个数组,其中两个数组的值都是唯一的。这是示例:
第一记录
{ Host:"abc.com" ArtId:"123", tags:[ "tag1", "tag2" ] }
第二纪录
{ Host:"abc.com" ArtId:"123", tags:[ "tag2", "tag3" ] }
在主机和artid上聚合后,我需要这样的结果:
{ Host: "abc.com", ArtId: "123", count :"2", tags:[ "tag1", "tag2", "tag3" ]}
我$addToset
在组语句中尝试过,但它给了我这样的标签:[["tag1","tag2"],["tag2","tag3"]]
您能帮我实现聚合吗
现代的版本应该使用$reduce
与$setUnion
所述初始后$group
如图所示:
db.collection.aggregate([
{ "$group": {
"_id": { "Host": "$Host", "ArtId": "$ArtId" },
"count": { "$sum": 1 },
"tags": { "$addToSet": "$tags" }
}},
{ "$addFields": {
"tags": {
"$reduce": {
"input": "$tags",
"initialValue": [],
"in": { "$setUnion": [ "$$value", "$$this" ] }
}
}
}}
])
找到$addToSet
运算符是正确的,但是在处理数组中的内容时,通常需要先进行处理$unwind
。这将对数组条目进行“反规范化”,并本质上对父文档进行“复制”,每个数组条目均作为字段中的奇异值。那就是您需要避免不使用该行为而看到的行为的原因。
虽然您的“计数”带来了一个有趣的问题,但是在初始$group
操作之后通过使用“双重展开”可以轻松解决:
db.collection.aggregate([
// Group on the compound key and get the occurrences first
{ "$group": {
"_id": { "Host": "$Host", "ArtId": "$ArtId" },
"tcount": { "$sum": 1 },
"ttags": { "$push": "$tags" }
}},
// Unwind twice because "ttags" is now an array of arrays
{ "$unwind": "$ttags" },
{ "$unwind": "$ttags" },
// Now use $addToSet to get the distinct values
{ "$group": {
"_id": "$_id",
"tcount": { "$first": "$tcount" },
"tags": { "$addToSet": "$ttags" }
}},
// Optionally $project to get the fields out of the _id key
{ "$project": {
"_id": 0,
"Host": "$_id.Host",
"ArtId": "$_id.ArtId",
"count": "$tcount",
"tags": "$ttags"
}}
])
最后一点$project
也存在,因为我在聚合管道的其他阶段中为每个字段使用了“临时”名称。这是因为存在一个优化,$project
即以“已存在”的顺序“复制”现有阶段中的字段,将其“出现在”任何“新”字段添加到文档之前。
否则输出将如下所示:
{ "count":2 , "tags":[ "tag1", "tag2", "tag3" ], "Host": "abc.com", "ArtId": "123" }
字段的顺序与您可能想到的顺序不同。确实微不足道,但这对某些人来说很重要,因此值得解释原因以及如何处理。
所以$unwind
呢,以保持项目的工作分开,而不是在数组中,并做了$group
第一个可以让你获得了“分组”键出现的“计数”。
在$first
以后使用运营商“保持”,即“计数”的值,因为它刚刚得到“复制”,每本的“标签”数组中值。无论如何,它们都是相同的值,所以没关系。选一个。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句