mongodb query multiple pairs using $in

蓝咒 提交于 2019-12-11 17:28:14

问题


I have a collection names with data (_id is omitted):

{first:"John", last:"Smith"},
{first:"Alice", last:"Johnson"},
{first:"Bob", last:"Williams"},
...

and {first, last} is a unique index.

I want to find a lot of names in names like:

db.names.find({$or: [{first:"Alice", last:"Brown"}, {first:"Bob", last:"White"}, ...]}

Can I use $in instead of $or to simplify this query?

===

I know in MySQL this following query:

SELECT * FROM names WHERE (first = 'Alice' AND last = 'Brown') OR (first = 'Bob' AND last = 'White') OR ...

can be simplified as:

SELECT * FROM names WHERE (first, last) IN (('Alice', 'Brown'), ('Bob','White') OR ...)

But I am unable to find the equivalent query syntax in MongoDB.


回答1:


Yes, it's possible to use $in to query MongoDb collections based on multiple values.

Try using the below syntax:

db.names.find.({ field: { $in: [<value1>, <value2>, ... <valueN> ] } })

for example in your case it looks like:

db.names.find({first: {$in: ["Alice","Brown","Bob", "White"]}})




回答2:


The following query can get us the expected output:

db.names.find({
    $expr:{
        $in:[
            {
                "first":"$first",
                "last":"$last"
            },
            [
                {
                    "first" : "Alice",
                    "last" : "Johnson"
                },
                {
                    "first" : "Bob",
                    "last" : "Williams"
                }
            ]
        ]
    }
}).pretty()

Data set:

{
    "_id" : ObjectId("5d81c3b7a832f81a9e02337b"),
    "first" : "John",
    "last" : "Smith"
}
{
    "_id" : ObjectId("5d81c3b7a832f81a9e02337c"),
    "first" : "Alice",
    "last" : "Johnson"
}
{
    "_id" : ObjectId("5d81c3b7a832f81a9e02337d"),
    "first" : "Bob",
    "last" : "Williams"
}

Output:

{
    "_id" : ObjectId("5d81c3b7a832f81a9e02337c"),
    "first" : "Alice",
    "last" : "Johnson"
}
{
    "_id" : ObjectId("5d81c3b7a832f81a9e02337d"),
    "first" : "Bob",
    "last" : "Williams"
}

Query Analysis: This query won't use the unique index you have created and I would recommend to go with the $or query.

Following are the winning plans:

$or query:

{
    "stage" : "COLLSCAN",
    "filter" : {
        "$expr" : {
            "$in" : [
                {
                    "first" : "$first",
                    "last" : "$last"
                },
                {
                    "$const" : [
                        {
                            "first" : "Alice",
                            "last" : "Johnson"
                        },
                        {
                            "first" : "Bob",
                            "last" : "Williams"
                        }
                    ]
                }
            ]
        }
    },
    "direction" : "forward"
}

$in query:

{
"stage" : "SUBPLAN",
    "inputStage" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "OR",
            "inputStages" : [
                {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "first" : 1,
                        "last" : 1
                    },
                    "indexName" : "first_1_last_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "first" : [ ],
                        "last" : [ ]
                    },
                    "isUnique" : true,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "first" : [
                            "[\"Alice\", \"Alice\"]"
                        ],
                        "last" : [
                            "[\"Brown\", \"Brown\"]"
                        ]
                    }
                },
                {
                    "stage" : "IXSCAN",
                    "keyPattern" : {
                        "first" : 1,
                        "last" : 1
                    },
                    "indexName" : "first_1_last_1",
                    "isMultiKey" : false,
                    "multiKeyPaths" : {
                        "first" : [ ],
                        "last" : [ ]
                    },
                    "isUnique" : true,
                    "isSparse" : false,
                    "isPartial" : false,
                    "indexVersion" : 2,
                    "direction" : "forward",
                    "indexBounds" : {
                        "first" : [
                            "[\"Bob\", \"Bob\"]"
                        ],
                        "last" : [
                            "[\"White\", \"White\"]"
                        ]
                    }
                }
            ]
        }
    }
}

You can see that the index is properly utilized in $or query and not used in the $in query.




回答3:


For this mysql query

SELECT * FROM names 
WHERE (first = 'Alice' AND last = 'Brown') 
OR (first = 'Bob' AND last = 'White') 
OR ...

can be use in mongodb as

db.names.find({
  $or: [
    { first: "Alice", last: "Brown" },
    { first: "Bob", last: "White" }, 
    ...
]})

For below mysql query

SELECT * FROM names 
WHERE (first, last) IN (('Alice', 'Brown'), ('Bob','White') OR ...)

You can not create mongodb $in query

db.names.find({
  $or: [
    { first: { $in: ["John", "Alice", "Bob"] } },
    { last: { $in: ["Smith", "Johnson", "Williams" ] } },
]})

Because it pass this result too

("John", "Johnson"),("John", "Williams"),("John", "Smith"),("John", "Williams")..

the best way is $or as ask in question

db.names.find({ 
  $or: [
    { first: "Alice", last: "Brown" }, 
    { first: "Bob", last: "White" },
     ...
]})

May be better solution present out there. I will update my answer if find any. Thanks



来源:https://stackoverflow.com/questions/57984354/mongodb-query-multiple-pairs-using-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!