hpohl
hpohl

Reputation: 325

findAndModify documents with same value in array of nested documents

The starting point is a collection that looks like this:

{
    "_id" : ObjectId("55b3c75d84251af91782ea07"),
    "arr" : [
        {
            "val" : "yes"
        },
        {
            "val" : "yes"
        }
    ]
}
{
    "_id" : ObjectId("55b3c76184251af91782ea08"),
    "arr" : [
        {
            "val" : "yes"
        },
        {
            "val" : "no"
        }
    ]
}
...

What I want to find are documents that only have yes's in arr.val. Please note that you will need to use findAndModify because I will need to update the documents afterwards.

What I've tried:

> db.coll.find({arr: {$all: [{$elemMatch: {val: 'yes'}}]}})
{ "_id" : ObjectId("55b3c75d84251af91782ea07"), "arr" : [ { "val" : "yes" }, { "val" : "yes" } ] }
{ "_id" : ObjectId("55b3c76184251af91782ea08"), "arr" : [ { "val" : "yes" }, { "val" : "no" } ] }
> db.coll.find({arr: {$all: [{val: 'yes'}]}})
{ "_id" : ObjectId("55b3c75d84251af91782ea07"), "arr" : [ { "val" : "yes" }, { "val" : "yes" } ] }
{ "_id" : ObjectId("55b3c76184251af91782ea08"), "arr" : [ { "val" : "yes" }, { "val" : "no" } ] }

Both versions still find both documents.

Upvotes: 0

Views: 53

Answers (1)

JohnnyHK
JohnnyHK

Reputation: 311895

You can do this using a combination of $eq and $ne to find docs that contain at least one arr element where val is 'yes', and no elements where its value is 'no':

db.coll.find({"arr.val": {$eq: 'yes', $ne: 'no'}})

Matches just the first doc:

{
    "_id" : ObjectId("55b3c75d84251af91782ea07"),
    "arr" : [
        {
            "val" : "yes"
        },
        {
            "val" : "yes"
        }
    ]
}

In a findAndModify:

db.coll.findAndModify({
    query: {"arr.val": {$eq: 'yes', $ne: 'no'}}, 
    update: {$set: {a: 1}}, 
    new: true
})

Upvotes: 1

Related Questions