简体   繁体   中英

Why does mongodb $all operator use all subarrays for quering?

I have some test documents that are structured as follows:

{
        "foo" : {
                "bar" : [
                        {
                                "a" : [
                                        "1",
                                        "4"
                                ]
                        },
                        {
                                "a" : [
                                        "1",
                                        "7"
                                ]
                        }
                ]
        }
}

Now I try to get all these documents where at least one of the "a" arrays contains the strings "1","4" and "7". (Note: I know that this example document should not be found!)

Now I query the db like this:

db.test.find({"foo.bar.a": {$all: ["1","4","7"]}})

In my opinion it should tell me that no document is found, but it finds the example document, as "1" and "4" are contained in the first "a" array and "7" is contained in the second "a" array.

Is this a bug of the $all operator, or is my query just wrong?

You can use the Aggregation Framework in MongoDB 2.2+ to $unwind the foo.bar.a array into a stream of documents that will match as expected.

Example query:

db.test.aggregate(
    // Could add a $match here to limit the number of relevant documents

    // Create a stream of documents from the foo.bar array
    { $unwind: '$foo.bar' },

    // Find arrays that have the desired elements
    { $match: {
        'foo.bar.a': { $all: ["1","4","7"] }
    }},

    // Re-group by original document _id with matching array elements
    { $group: {
        _id: "$_id",
        'a': { $push: '$foo.bar.a' }
    }}
)

Sample result:

{
    "result" : [
        {
            "_id" : ObjectId("50f08b392aa92c6de18aa70a"),
            "a" : [
                [
                    "7",
                    "4",
                    "1"
                ]
            ]
        },
        {
            "_id" : ObjectId("50f08b322aa92c6de18aa709"),
            "a" : [
                [
                    "1",
                    "4",
                    "7"
                ]
            ]
        }
    ],
    "ok" : 1
}

Is this what you need? One element whose "a" array contains all specified values.

db.test.find({"foo.bar": {$elemMatch: {"a": {$all: ["1", "4", "7"]}}}})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM