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.
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.