MongoDB聚合 - 匹配数组中的值

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或更高版本,那么您应该这样做以比较文档中的这些元素.


Syl*_*oux 8

根据@ 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将过滤掉不需要的文档.


chr*_*dam 6

更有效的方法将涉及使用$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)


Ral*_*lph 5

回答有点晚,但这提出了另一个解决方案:

通过使用addFields并单独匹配,这提供了比编辑更多的灵活性.您可以显示多个字段,然后根据结果使用其他匹配逻辑.

db.applications.aggregate([
    {$addFields: {"containsValueInArray": {$cond:[{$setIsSubset: [["valueToMatch"], "$arrayToMatchIn"]},true,false]}}},
    {$match: {"containsValueInArray":true}}
]);
Run Code Online (Sandbox Code Playgroud)


use*_*814 5

您可以在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 + $in3.4版本中表达。

db.collection_name.aggregate({
  "$redact": {
    "$cond": [
      {
        "$in": [
          "$value",
          "$array"
        ]
      },
      "$$KEEP",
      "$$PRUNE"
    ]
  }
})
Run Code Online (Sandbox Code Playgroud)