MongoDB update multiple subdocuments with or query

2019-03-05 11:43发布

I want to make an update query for multiple subdocuments at once. I will be setting all the subdocuments statuses to passive where they satisfy the condition I give on query.

db.deduplications.update(  
{ $and: [ 
    { "_id": "189546D623FC69E3B693FDB679DBC76C" }, 
    { "DeviceVersionPairs.DeviceId": ObjectId("5822d0606bfdcd6ec407d9b9") }, 
    { "DeviceVersionPairs.CloudFolderId": ObjectId("5823110e6bfdd46ec4357582") },
    { "DeviceVersionPairs.CloudFileId": ObjectId("582311168cd396223499942a") },
    { "DeviceVersionPairs.VersionId": ObjectId("582311168cd396223499942b") }
] },
{ $set: { "DeviceVersionPairs.$.Status": "passive" }});

Above query finds exactly one subdocument, then it makes the update as I want it. But;

db.deduplications.update(  
{ $or: [ { $and: [ 
        { "_id": "189546D623FC69E3B693FDB679DBC76C" }, 
        { "DeviceVersionPairs.DeviceId": ObjectId("5822d0606bfdcd6ec407d9b9") }, 
        { "DeviceVersionPairs.CloudFolderId": ObjectId("5823110e6bfdd46ec4357582") },
        { "DeviceVersionPairs.CloudFileId": ObjectId("582311168cd396223499942a") },
        { "DeviceVersionPairs.VersionId": ObjectId("582311168cd396223499942b") }
    ] } ,   
    { $and: [ 
        { "_id": "189546D623FC69E3B693FDB679DBC76C" }, 
        { "DeviceVersionPairs.DeviceId": ObjectId("56dfe1356caaea14a819f1e4") }, 
        { "DeviceVersionPairs.CloudFolderId": ObjectId("583fb4bc6e7f341874f13bfc") }, 
        { "DeviceVersionPairs.CloudFileId": ObjectId("583fb539e015b8a53fb71872") }, 
        { "DeviceVersionPairs.VersionId": ObjectId("583fb4ca6e7f331874213584") }
    ] } ] },
{ $set: { "DeviceVersionPairs.$.Status": "passive" }});

When I populate the query segment with an or, and add the other items it gives error:

WriteResult({
    "nMatched" : 0,
    "nUpserted" : 0,
    "nModified" : 0,
    "writeError" : {
        "code" : 16837,
        "errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: DeviceVersionPairs.$.Status"
    }
})

What am I missing here?

4条回答
甜甜的少女心
2楼-- · 2019-03-05 11:50

You got this error

The positional operator did not find the match needed from the query

because of your second query matched with multiple sub-document. Currently it is not possible to use the positional operator to update all items in an array using positional operator.

so to solve your problem you can follow this process

  1. Find document using _id and to find sub document using $elemMatch and then

  2. update each sub document and save document again

can try like this:

db.deduplications.find(  
{ $or: [ {
         "_id": ObjectId("583fc558668bde730a460e11") , 
        "DeviceVersionPairs":{
            $elemMatch:{ "DeviceId": ObjectId("5822d0606bfdcd6ec407d9b9") , 
            "CloudFolderId": ObjectId("5823110e6bfdd46ec4357582") ,
            "DeviceVersionPairs.CloudFileId": ObjectId("582311168cd396223499942a") ,
            "DeviceVersionPairs.VersionId": ObjectId("582311168cd396223499942b") }}
    } ,   
    { 
        "_id": ObjectId("583fc558668bde730a460e11") , 
        "DeviceVersionPairs":{
            $elemMatch:{ "DeviceId": ObjectId("56dfe1356caaea14a819f1e4") , 
            "CloudFolderId": ObjectId("583fb4bc6e7f341874f13bfc") , 
            "CloudFileId": ObjectId("583fb539e015b8a53fb71872") , 
            "VersionId": ObjectId("583fb4ca6e7f331874213584") }}
    } ] 
}).forEach(function (doc) {
    doc.DeviceVersionPairs.forEach(function (device) {
      device.status = 'passive';
    });
    db.deduplications.save(doc);
 });
查看更多
疯言疯语
3楼-- · 2019-03-05 11:53

Not so sure about what do you want, but if I were right, what you want may be $elemMatch.

Refer to MongoDB Update Manual , and $elemMatch

When you wanna query into embedded documents, you can't use $and and $or directly, this is some kind of 'bug' of mongodb.

查看更多
可以哭但决不认输i
4楼-- · 2019-03-05 11:57

Use method UpdateMany() to update documents. According to framework and langauage this method will be different like Update({multi : true}); or UpdateAll({});`

For example :

db.collection.updateMany(
   <filter>,
   <update>
);

Use $set to write.

Ref: https://docs.mongodb.com/v3.2/reference/method/db.collection.updateMany/

try {
   db.restaurant.updateMany(
      { $or: []
      },
      { $set: { "DeviceVersionPairs.$.Status": "passive" } }
   );
} catch (e) {
   print(e);
} 
查看更多
疯言疯语
5楼-- · 2019-03-05 12:08

I have run below query. And it is working fantastic.

db.mm.update( { $or: [ {$and: [{"_id": ObjectId("581d18d41b6c5c752f11c87a")}] }, 
                       {$and: [{"_id": ObjectId("581a1a671b6c5c752f11c87b")}] } 
               ] 
          }, {$set : {"name": "abc3"}});

If first document not found , second one is updated. And if 1st one is found it is updating only 1st one.

You can see that in your question -> Error message it is showing "nMatched" : 0 . It is not finding any documents. Confirm all ID's and reference ID's.

查看更多
登录 后发表回答