eml*_*002 19 mongodb aggregation-framework
我有一个我正在进行聚合的集合,我基本上已经把它归结为
{array:[1,2,3], value: 1},
{array:[1,2,3], value: 4}
Run Code Online (Sandbox Code Playgroud)
如何执行聚合匹配以检查值是否在数组中?我尝试使用,{$match: {"array: {$in: ["$value"]}}}但它没有找到任何东西.
我希望输出(如果使用上面的例子)是:
{array:[1,2,3], value:1}
Run Code Online (Sandbox Code Playgroud)
Bla*_*ven 13
如上所述,这$where是一个很好的选择,您不需要在聚合管道中继续逻辑.
但是,如果你这样做,那么使用$redact,$map将"值"转换为数组并使用$setIsSubSet比较.这是最快的方法,因为您不需要使用$unwind以下方法复制文档:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": { "$setIsSubset": [
{ "$map": {
"input": { "$literal": ["A"] },
"as": "a",
"in": "$value"
}},
"$array"
]},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
Run Code Online (Sandbox Code Playgroud)
该$redact管道运营商允许的范围内的逻辑条件的等待处理$cond,并使用特别行动$$KEEP"养",其中的逻辑条件为真或文档$$PRUNE为"删除",其中条件是假文件.
这允许它像$project后续工作一样工作$match,但在单个管道阶段更有效.
考虑到这些是本机编码运算符而不是JavaScript,那么它可能是"最快"的匹配方式.因此,如果您使用的是MongoDB 2.6或更高版本,那么您应该这样做以比较文档中的这些元素.
根据@ chridam的回答略有不同:
db.test.aggregate([
{ "$unwind": "$array" },
{ "$group": {
_id: { "_id": "$_id", "value": "$value" },
array: { $push: "$array" },
mcount: { $sum: {$cond: [{$eq: ["$value","$array"]},1,0]}}
}
},
{ $match: {mcount: {$gt: 0}}},
{ "$project": { "value": "$_id.value", "array": 1, "_id": 0 }}
])
Run Code Online (Sandbox Code Playgroud)
我们的想法是$unwind和$group背面的阵列,在计数mcount匹配所述值的项数.之后,简单的$matchon mcount > 0将过滤掉不需要的文档.
更有效的方法将涉及使用$redact运算符的单个管道,如下所示:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$setIsSubset": [
["$value"],
"$array"
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
Run Code Online (Sandbox Code Playgroud)
对于不支持的早期版本的MongoDB $redact(版本<2.6),请考虑使用该$unwind运算符的此聚合管道:
db.collection.aggregate([
{ "$unwind": "$array" },
{
"$project": {
"isInArray": {
"$cond": [
{ "$eq": [ "$array", "$value" ] },
1,
0
]
},
"value": 1,
"array": 1
}
},
{ "$sort": { "isInArray": -1 } },
{
"$group": {
"_id": {
"_id": "$_id",
"value": "$value"
},
"array": { "$push": "$array" },
"isInArray": { "$first": "$isInArray" }
}
},
{ "$match": { "isInArray": 1 } },
{ "$project": { "value": "$_id.value", "array": 1, "_id": 0 } }
])
Run Code Online (Sandbox Code Playgroud)
回答有点晚,但这提出了另一个解决方案:
通过使用addFields并单独匹配,这提供了比编辑更多的灵活性.您可以显示多个字段,然后根据结果使用其他匹配逻辑.
db.applications.aggregate([
{$addFields: {"containsValueInArray": {$cond:[{$setIsSubset: [["valueToMatch"], "$arrayToMatchIn"]},true,false]}}},
{$match: {"containsValueInArray":true}}
]);
Run Code Online (Sandbox Code Playgroud)
您可以在3.6版本的常规查询中使用聚合表达式。
db.collection_name.find({"$expr": {"$in": ["$value", "$array"]}})
Run Code Online (Sandbox Code Playgroud)
使用聚合:
您可以$match + $expr在当前3.6版本中使用。
db.collection_name.aggregate({"$match": {"$expr": {"$in": ["$value", "$array"]}}})
Run Code Online (Sandbox Code Playgroud)
您可以尝试$redact + $in在3.4版本中表达。
db.collection_name.aggregate({
"$redact": {
"$cond": [
{
"$in": [
"$value",
"$array"
]
},
"$$KEEP",
"$$PRUNE"
]
}
})
Run Code Online (Sandbox Code Playgroud)