Search code examples
node.jsarraysmongodbinsert-updateupsert

Problems with "updateMany" and "$pull" on array properties


I have the following object in my mongodb:

{ 
  "item": {
    "id": "/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8=",
    "status": {
      "likes": [
        "HU0HKFoL2YQuQ2WrYhj0rYoFbRkwJ0EJEf4ML7vAp2Q="
      ]
    }
  }
}

Now I want to update my collection, and pull the value "/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8=" from all documents in the collection who have this value in their item.status.liles array.

When I use the tool Robo 3T, I can put into the command line:

db.getCollection('mycollection').update({"item.status.likes": "/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8=" }, { "$pull":{"item.status.likes": "/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8="}})

And it says Updated 0 record(s) in 2ms when I execute the command (which is correct, since there is no document matching).

Now when I do the same in Node.JS code, like this:

let filter = {item.status.likes: '/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8='};
let obj = {"$pull":{"item.status.likes":"/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8="}}

collection.updateMany(filter, obj, { upsert: true }, (err, info) => {...});

I get MongoError: Cannot apply $pull to a non-array value instead.

If I change it to:

collection.updateMany({}, obj, { upsert: true }, (err, info) => {...});

I get no error. This leads me to believe that there is a difference between "no filter" and "empty result set", and $pull does not work on the latter.

Why is this? I also tried with different "$pull"-syntax (e.g. {"item":{"status":{"likes"... vs item.status.likes) but this didnt change anything.


Solution

  • The error happens when there is no single document matching the filter because of upsert: true.

    It tells mongo to insert a new document with fields from the filter, which makes following document:

    { 
      "item": {
        "status": {
          "likes": "/Ed/6wigZ9LTLs2mPDWDzOFD/he0vbUEvQBl2Bga/T8="
        }
      }
    }
    

    Then it tries to apply the update to this document calling $pull on the string which results with the error.

    The Robo3T version works because the update is upsert: false by default.