mongodb 如何使用MongoDB过滤子文档中的数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15117030/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 13:05:02  来源:igfitidea点击:

How to filter array in subdocument with MongoDB

mongodbfiltermongodb-queryaggregation-framework

提问by chenka

I have array in subdocument like this

我在子文档中有这样的数组

{
    "_id" : ObjectId("512e28984815cbfcb21646a7"),
    "list" : [
        {
            "a" : 1
        },
        {
            "a" : 2
        },
        {
            "a" : 3
        },
        {
            "a" : 4
        },
        {
            "a" : 5
        }
    ]
}

Can I filter subdocument for a > 3

我可以过滤子文档> 3

My expect result below

我的预期结果如下

{
    "_id" : ObjectId("512e28984815cbfcb21646a7"),
    "list" : [
        {
            "a" : 4
        },
        {
            "a" : 5
        }
    ]
}

I try to use $elemMatchbut returns the first matching element in the array

我尝试使用$elemMatch但返回数组中的第一个匹配元素

My query:

我的查询:

db.test.find( { _id" : ObjectId("512e28984815cbfcb21646a7") }, { 
    list: { 
        $elemMatch: 
            { a: { $gt:3 } 
            } 
    } 
} )

The result return one element in array

结果返回数组中的一个元素

{ "_id" : ObjectId("512e28984815cbfcb21646a7"), "list" : [ { "a" : 4 } ] }

and I try to use aggregate with $matchbut not work

我尝试使用聚合$match但不起作用

db.test.aggregate({$match:{_id:ObjectId("512e28984815cbfcb21646a7"), 'list.a':{$gte:5}  }})

It's return all element in array

它返回数组中的所有元素

{
    "_id" : ObjectId("512e28984815cbfcb21646a7"),
    "list" : [
        {
            "a" : 1
        },
        {
            "a" : 2
        },
        {
            "a" : 3
        },
        {
            "a" : 4
        },
        {
            "a" : 5
        }
    ]
}

Can I filter element in array to get result as expect result?

我可以过滤数组中的元素以获得预期结果吗?

回答by JohnnyHK

Using aggregateis the right approach, but you need to $unwindthe listarray before applying the $matchso that you can filter individual elements and then use $groupto put it back together:

使用aggregate是正确的做法,但你需要$unwindlist应用前阵列$match,这样就可以过滤单个元素,然后用$group把它重新走到一起:

db.test.aggregate([
    { $match: {_id: ObjectId("512e28984815cbfcb21646a7")}},
    { $unwind: '$list'},
    { $match: {'list.a': {$gt: 3}}},
    { $group: {_id: '$_id', list: {$push: '$list.a'}}}
])

outputs:

输出:

{
  "result": [
    {
      "_id": ObjectId("512e28984815cbfcb21646a7"),
      "list": [
        4,
        5
      ]
    }
  ],
  "ok": 1
}

MongoDB 3.2 Update

MongoDB 3.2 更新

Starting with the 3.2 release, you can use the new $filteraggregation operator to do this more efficiently by only including the listelements you want during a $project:

从 3.2 版本开始,您可以使用新的$filter聚合运算符来更有效地执行此操作,方法是list在 a 期间仅包含您想要的元素$project

db.test.aggregate([
    { $match: {_id: ObjectId("512e28984815cbfcb21646a7")}},
    { $project: {
        list: {$filter: {
            input: '$list',
            as: 'item',
            cond: {$gt: ['$$item.a', 3]}
        }}
    }}
])

回答by keshav

Above solution works best if multiple matching sub documents are required. $elemMatchalso comes in very use if single matching sub document is required as output

如果需要多个匹配的子文档,上述解决方案效果最佳。 如果需要单个匹配的子文档作为输出,$elemMatch也非常有用

db.test.find({list: {$elemMatch: {a: 1}}}, {'list.$': 1})

Result:

结果:

{
  "_id": ObjectId("..."),
  "list": [{a: 1}]
}

回答by Rahul

Use $filter aggregation

使用$filter 聚合

Selects a subset of the array to return based on the specified condition. Returns an array with only those elements that match the condition. The returned elements are in the original order.

根据指定条件选择要返回的数组子集。返回一个仅包含与条件匹配的元素的数组。返回的元素按原始顺序排列。

db.test.aggregate([
    {$match: {"list.a": {$gt:3}}}, // <-- match only the document which have a matching element
    {$project: {
        list: {$filter: {
            input: "$list",
            as: "list",
            cond: {$gt: ["$$list.a", 3]} //<-- filter sub-array based on condition
        }}
    }}
]);