【问题标题】:How to filter array of sub-documents?如何过滤子文档数组?
【发布时间】:2017-02-09 17:53:49
【问题描述】:

我的文档结构如下:

{ 
"_id" : ObjectId("564d2702d4c68225cb00726f"), 
"list" : [
    {
        "a" : NumberInt(1), 
        "test" : "public"
    }, 
    {
        "a" : NumberInt(2), 
        "test" : "public"
    }, 
    {
        "a" : NumberInt(3), 
        "test" : "public"
    }, 
    {
        "a" : NumberInt(4), 
        "test" : "public"
    }, 
    {
        "a" : NumberInt(5), 
        "test" : "public"
    }
],
"other_fields": ""}

我可以在 (1, 5) 中过滤子文档吗

下面是我的预期结果

{
"_id" : ObjectId("564d2702d4c68225cb00726f"),
"list" : [
    {
        "a" : NumberInt(1),
        "test" : "public"
    },
    {
        "a" : NumberInt(5),
        "test" : "public"
    }
]}

我尝试使用$elemMatch,但是当我使用$in时,发生了错误。

【问题讨论】:

  • 您必须使用aggregate 才能获得所需的结果。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

从 MongoDB 3.2 开始,我们可以使用$filter 操作符来有效地做到这一点。在$filter 的条件表达式中,我们需要使用$setIsSubset 运算符来检查给定值是否在数组中。这主要是因为我们不能在$project阶段使用$in查询运算符。

db.collection.aggregate([
    { "$project": { 
        "list": { 
            "$filter": { 
                "input": "$list", 
                "as": "lst", 
                "cond": { "$setIsSubset": [ [ "$$lst.a" ], [ 1, 5 ] ] }
            } 
        } 
    }}
])

从 MongoDB 3.0.x 向后,您需要一种不同的、效率较低的方法,使用 $map 运算符和 $setDifference 运算符。

db.collection.aggregate([
    { "$project": { 
        "list": { 
            "$setDifference": [ 
                { "$map": { 
                    "input": "$list", 
                    "as": "lst", 
                    "in": { 
                        "$cond": [
                            { "$setIsSubset": [ [ "$$lst.a" ], [ 1, 5 ] ] },
                            "$$lst",
                            false
                        ] 
                    } 
                }}, 
                [false] 
            ]
        }
    }}
])

【讨论】:

    【解决方案2】:

    尝试以下查询:-

    db.collection.aggregate([
    { 
        "$match": {
           $or[{ "list.a": NumberInt(1)}, {{ "list.a": NumberInt(5)}}]
        }
    },
    {
        "$project": {
            "list": {
                "$setDifference": [
                    {
                        "$map": {
                            "input": "$list",
                            "as": "o",
                            "in": {
                                "$cond": [
                                    {  
                                         $or[{ "list.a": NumberInt(1)}, 
                                             {{ "list.a": NumberInt(5)}}]
                                    },
                                    "$$o",
                                    false
                                ]
                            }
                        }
                    },
                    [false]
                ]
            }
        }
    }
    ])
    

    通过使用查询结果将是:-

    {
        "_id" : ObjectId("564d2702d4c68225cb00726f"),
        "list" : [
        {
            "a" : NumberInt(1),
            "test" : "public"
        },
        {
            "a" : NumberInt(5),
            "test" : "public"
        }
    ]}
    

    【讨论】:

    • 如果您使用的是 mongodb 3.2.x,您可以选择第一个答案。低于 3.2.x 到 2.6.X 我的答案将是解决方案。
    猜你喜欢
    • 1970-01-01
    • 2019-06-25
    • 2018-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-07-18
    • 2018-08-11
    • 1970-01-01
    相关资源
    最近更新 更多