gpt4 book ai didi

MongoDB聚合选择性项目

转载 作者:行者123 更新时间:2023-12-02 04:30:18 24 4
gpt4 key购买 nike

我在聚合聚合期间遇到了 reshape 文档的问题。基本上我想根据条目的类型将条目推送到字段中。我的结构如下:

_id: P1
entities: [{type: A, val: X}, {type: B, val: X}, {type: A, val: Y}]
...

我想 $unwind 和 $project 这些实体,以便获得如下结构:

_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]

这会扰乱计数。我的第二个想法是过滤数组以删除空值。但我没有找到删除实体的方法,因为 $cond 再次不允许我指定空/“不执行任何操作”的其他情况。

我有一种感觉,它可以按照类型和内容进行分组,并匹配所需的类型,但是因为我有很多类型和任意分组,导致分组树,所以这可能会变得非常复杂。非常欢迎提出想法或错误提示。

谢谢

编辑:基于接受的答案的解决方案

我必须稍微调整它,以过滤类型的所有内容都为空的情况,因为否则它会在匹配过程中丢失,并且因为我想保留这些知识。谢谢!

{$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" }
}}

最佳答案

您似乎走在正确的道路上,只是有不同的方法可以从条件中删除这些 false 值。您不能让它返回任何内容,但您可以删除不需要的值。

如果您确实想要“集合”并且您有 MongoDB 2.6 或更高版本可用,那么您基本上可以使用 $setDifference 过滤掉 false 值:

db.entities.aggregate([
{ "$unwind": "$entities" },
{ "$group": {
"_id": "$_id",
"A": {
"$addToSet": {
"$cond": [
{ "$eq": [ "$entities.type", "A" ] },
"$entities.val",
false
]
}
},
"B": {
"$addToSet": {
"$cond": [
{ "$eq": [ "$entities.type", "B" ] },
"$entities.val",
false
]
}
}
}},
{ "$project": {
"A": {
"$setDifference": [ "$A", [false] ]
},
"B": {
"$setDifference": [ "$B", [false] ]
}
}}
])

或者只是使用$map作为一个步骤内部运算符 $project :

db.entities.aggregate([
{"$project": {
"A": {
"$setDifference": [
{
"$map": {
"input": "$entities",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.type", "A" ] },
"$$el.val",
false
]
}
}
},
[false]
]
},
"B": {
"$setDifference": [
{
"$map": {
"input": "$entities",
"as": "el",
"in": {
"$cond": [
{ "$eq": [ "$$el.type", "B" ] },
"$$el.val",
false
]
}
}
},
[false]
]
}
}}
])

或者以其他方式留在将军$unwind$match运算符来过滤这些:

db.entities.aggregate([
{ "$unwind": "$entities" },
{ "$group": {
"_id": "$_id",
"A": {
"$push": {
"$cond": [
{ "$eq": [ "$entities.type", "A" ] },
"$entities.val",
false
]
}
},
"B": {
"$push": {
"$cond": [
{ "$eq": [ "$entities.type", "B" ] },
"$entities.val",
false
]
}
}
}},
{ "$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" }
}}
])

使用 $push对于普通数组或 $addToSet独特的套装。

关于MongoDB聚合选择性项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24496327/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com