在聚合分组期间,我遇到了重塑文档的问题 . 基本上我想根据类型将条目推送到字段 . 我的结构如下:
_id: P1
entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}]
...
我想$ unwind和$投影这些实体,以便获得如下结构:
_id: P1
A: [X]
B: []
_id: P1
A: [Y]
B: []
_id: P1
A: []
B: [X]
所以我可以用A或B或两者进行分组,即
$group: {
_id: {
A: $A,
B: $B
}
count: {$sum : 1}
我以为我可以做到:
$unwind: $entities
$project: {
id: §id
A: {"$cond":[{"$eq":["$type","A"]},"$code"]}
B: {"$cond":[{"$eq":["$type","B"]},"$code"]}
}
$group: {
_id: "$id"
A: {$addToSet : "$A"}
}
或失败的东西
$unwind: $entities
$group: {
_id: "$id"
A: {"$cond":[{"$eq":["$type","A"]},$push: "$code", null]}
...
}
但是这两个版本都失败了,因为我对其他内容无能为力,而且我没有设法在条件内使用$ push . 我得到的最接近的是项目取决于类型,但由于我找不到在没有匹配时不向场添加任何内容的方法,我最终得到:
_id: P1
A: [X,null,Y]
B: [null,X,null]
这弄乱了计数 . 我的第二个想法是过滤数组以删除null . 但我没有找到删除实体的方法,因为再次$ cond不会让我指定一个空/“什么都不做”的情况 .
我觉得它可以通过类型和内容进行分组以及所需类型的匹配,但由于我有许多类型和任意分组导致分组树,这可能会变得非常复杂 . 对错误的想法或提示将非常受欢迎 .
谢谢
EDIT: 基于接受的anwser的解决方案
我不得不稍微调整它,以过滤一个类型的所有内容都为null的情况,因为否则它会在匹配期间丢失,因为我想保留这些知识 . 谢谢!
{$project:{
A: {$cond: [
{$eq: ["$A", [false]]},
["N/A"],
"$A"
]},
B: {$cond: [
{$eq: ["$B", [false]]},
["N/A"],
"$B"
]},
}},
{ "$unwind": "$A" },
{ "$match": { "A": { "$ne": false } } },
{ "$group": {
"_id": "$_id",
"A": { "$push": "$A" },
"B": { "$first": "$B" }
}},
{ "$unwind": "$B" },
{ "$match": { "B": { "$ne": false } } },
{ "$group": {
"_id": "$_id",
"A": { "$first": "$A" },
"B": { "$push": "$B" }
}}
1 回答
你似乎走在正确的轨道上,只有不同的方法从条件中删除
false
的值 . 你不能让它什么都不返回,但你可以摆脱你不想要的值 .如果你真的想要"sets"并且你有MongoDB 2.6或更高版本可用,那么你基本上使用$setDifference过滤掉
false
值:或者只是在$project中使用$map运算符的一步:
或者与一般的$unwind和$match运算符一起使用来过滤这些:
对正常数组使用$push或对于唯一集使用$addToSet .