简体   繁体   中英

How to retrieve the document exactly matching a given value in mongodb

from the mongodb official documentation :

The following examples query against the inventory collection with the following documents:

{ _id: 1, item: { name: "ab", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 2, item: { name: "cd", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 3, item: { name: "ij", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "xy", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 5, item: { name: "mn", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

The following example queries the inventory collection to select all documents where the tags array equals exactly the specified array or the tags array contains an element that equals the array [ "A", "B" ].

db.inventory.find( { tags: { $eq: [ "A", "B" ] } } )

The query is equivalent to:

db.inventory.find( { tags: [ "A", "B" ] } )

Both queries match the following documents:

{ _id: 3, item: { name: "ij", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 5, item: { name: "mn", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Now i wish to know how i can query in order to get the document(s) having its tags field exactly equal to [ "A", "B" ] and not containing it alone or among other elements ? i want the result for the example above will be only the first document returned :

{ _id: 3, item: { name: "ij", code: "456" }, qty: 25, tags: [ "A", "B" ] }

If you want to only extract the documents that accurately match the array that you provide, you can add a $size operand in your query:

db.inventory.find({
    $and: [
        { tags: "A" },
        { tags: "B" },
        { tags: { $size: 2 }}
    ]
});

The above query will only match documents that have the tags field equal to the specified array, with its elements in that exact order.

The solution provided by chridam in the comments is a more elegant solution:

db.inventory.find({ "tags": { "$all": [ "A", "B" ], "$size": 2 } })

UPDATE:

I inserted the documents you provided in a local MongoDB instance to test my and chridam's queries, and they both return the same result set from the documents that you provided:

{ "_id" : ObjectId("580146168ff3eea72fd1edc7"), "item" : { "name" : "ij", "code" : "456" }, "qty" : 25, "tags" : [ "A", "B" ] }
{ "_id" : ObjectId("580146168ff3eea72fd1edc8"), "item" : { "name" : "xy", "code" : "456" }, "qty" : 30, "tags" : [ "B", "A" ] }

As you can see, it matches the elements of the array and the size, but it does not account for the order in which they appear in the array.

Therefore, I explored different approaches in order to provide a working solution for the outcome you specified, which is to match both the exact contents of the array, as well as their order.

I managed to write the following query using the $where operator, which complies with your request:

db.items.find({ $where: function() {
    var arr = ["A", "B"],
        tags = this.tags;

    if(tags.length !== arr.length) {
        return false;
    }

    for(var i = 0; i < tags.length; i++) {
        if(tags[i] !== arr[i]) {
            return false;
        }
    }

    return true;
}});

/*
 * RESULT SET
 */
{ "_id" : ObjectId("580146168ff3eea72fd1edc7"), "item" : { "name" : "ij", "code" : "456" }, "qty" : 25, "tags" : [ "A", "B" ] }

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