MongoDB 聚合 - 匹配数组中的值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30537317/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MongoDB Aggregation - match if value in array
提问by eml002
I have a collection that I'm performing an aggregation on and I've basically gotten it down to
我有一个正在执行聚合的集合,我基本上已经把它归结为
{array:[1,2,3], value: 1},
{array:[1,2,3], value: 4}
How would I perform an aggregation match to check if the value is in the array? I tried using {$match: {"array: {$in: ["$value"]}}}
but it doesn't find anything.
我将如何执行聚合匹配以检查该值是否在数组中?我尝试使用{$match: {"array: {$in: ["$value"]}}}
但它没有找到任何东西。
I would want the output (if using the above as an example) to be:
我希望输出(如果使用上面的例子)是:
{array:[1,2,3], value:1}
采纳答案by Sylvain Leroux
A slight variation based on @chridam's answer:
根据@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 }}
])
The idea is to $unwind
and $group
back the array, counting in mcount
the number of items matching the value. After that, a simple $match
on mcount > 0
will filter out unwanted documents.
我们的想法是$unwind
和$group
背面的阵列,计数在mcount
匹配值的项数。之后,一个简单的$match
onmcount > 0
将过滤掉不需要的文件。
回答by Blakes Seven
As stated, $where
is a good option where you do not need to continue the logic in the aggregation pipeline.
如上所述,这$where
是一个不错的选择,您不需要在聚合管道中继续逻辑。
But if you do then use $redact
, with $map
to transform the "value" into an array and use of $setIsSubSet
to compare. It is the fastest way to do this since you do not need to duplicate documents using $unwind
:
但是,如果您这样做,则使用$redact
, with$map
将“值”转换为数组并使用 of$setIsSubSet
进行比较。这是最快的方法,因为您不需要使用$unwind
以下方法复制文档:
db.collection.aggregate([
{ "$redact": {
"$cond": {
"if": { "$setIsSubset": [
{ "$map": {
"input": { "$literal": ["A"] },
"as": "a",
"in": "$value"
}},
"$array"
]},
"then": "$$KEEP",
"else": "$$PRUNE"
}
}}
])
The $redact
pipeline operator allows the proccessing of a logical condition within $cond
and uses the special operations $$KEEP
to "keep" the document where the logical condition is true or $$PRUNE
to "remove" the document where the condition was false.
该$redact
管道运营商允许的范围内的逻辑条件的等待处理$cond
,并使用特别行动$$KEEP
“养”,其中的逻辑条件为真或文档$$PRUNE
为“删除”,其中条件是假文件。
This allows it to work like $project
with a subsequent $match
, but in a single pipeline stage which is more efficient.
这允许它像$project
随后的$match
,但在更有效的单个管道阶段中工作。
Considering these are native coded operators and not JavaScript then it is likely "the" fastest way to perform your match. So provided you are using a MongoDB 2.6 version or above, then this is the way you should be doing it to compare these elements in your document.
考虑到这些是本机编码的运算符而不是 JavaScript,那么它可能是执行匹配的“最快”方式。因此,如果您使用的是 MongoDB 2.6 或更高版本,那么您应该采用这种方式来比较文档中的这些元素。
回答by Sagar Veeram
You can use aggregation expression in regular query in 3.6 version.
3.6 版本可以在正则查询中使用聚合表达式。
db.collection_name.find({"$expr": {"$in": ["$value", "$array"]}})
Using Aggregation:
使用聚合:
You can use $match + $expr
in current 3.6
version.
您可以$match + $expr
在当前3.6
版本中使用。
db.collection_name.aggregate({"$match": {"$expr": {"$in": ["$value", "$array"]}}})
You can try $redact + $in
expression in 3.4
version.
您可以$redact + $in
在3.4
版本中尝试表达式。
db.collection_name.aggregate({
"$redact": {
"$cond": [
{
"$in": [
"$value",
"$array"
]
},
"$$KEEP",
"$$PRUNE"
]
}
})
回答by chridam
A more efficient approach would involve a single pipeline that uses the $redact
operator as follows:
一种更有效的方法将涉及使用$redact
运算符的单个管道,如下所示:
db.collection.aggregate([
{
"$redact": {
"$cond": [
{
"$setIsSubset": [
["$value"],
"$array"
]
},
"$$KEEP",
"$$PRUNE"
]
}
}
])
For earlier versions of MongoDB that do not support $redact
(versions < 2.6) then consider this aggregation pipeline that uses the $unwind
operator:
对于不支持$redact
(版本 < 2.6)的早期 MongoDB 版本,请考虑使用该$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 } }
])
回答by Ralph
A little late to answer but this presents another solution:
回答有点晚,但这提出了另一种解决方案:
By using addFields and match separately, this gives more flexibility than the redact. You can expose several fields and then use other matching logic together based on the results.
通过分别使用 addFields 和 match,这比 redact 提供了更大的灵活性。您可以公开多个字段,然后根据结果一起使用其他匹配逻辑。
db.applications.aggregate([
{$addFields: {"containsValueInArray": {$cond:[{$setIsSubset: [["valueToMatch"], "$arrayToMatchIn"]},true,false]}}},
{$match: {"containsValueInArray":true}}
]);
回答by styvane
回答by Richard Mao
Try the combination of $eq and $setIntersection
试试 $eq 和 $setIntersection 的组合
{$group :{
_id: "$id",
yourName : { $sum:
{ $cond :[
{$and : [
{$eq:[{$setIntersection : ["$someArrayField", ["$value"]] },["$value"]]}
]
},1,0]
}
} }
} }
回答by F.H.
i prefer without grouping, there's an easy approach since v.3.2
我更喜欢不分组,自 v.3.2 以来有一个简单的方法
...aggregate([
{
$addFields: {
arrayFilter: {
$filter: {
input: '$array',
as: 'item',
cond: ['$$item', '$value']
}
}
}
},
{
$unwind: '$arrayFilter'
},
{
$project: {
arrayFilter: 0
}
}
]);
- Add a temporary filter field
- $unwind on the resulting array (pipeline results with empty arrays get removed)
- (optional) remove filter field from result via project
- 添加临时过滤字段
- $unwind 在结果数组上(删除带有空数组的管道结果)
- (可选)通过项目从结果中删除过滤器字段
回答by vajid khokhar
You can do it with simple $project & $match
你可以用简单的 $project & $match
db.test.aggregate([{
$project: {
arrayValue: 1,
value: 1,
"has_same_value" : { $in: ["$value", "$arrayValue"] }
}
},
{
$match: {has_same_value: true}
},
{
$project: {has_same_value: 0}
}])
回答by Kevin007
"$match": { "name": { "$in":["Rio","Raja"] }} }])