I am trying to unset all values in a document that's embedded in an array. Let's say I have a collection coll
with array things
,开发者_开发技巧 containing a value myval
. I want to unset myval
. This looks like:
{ things: [{ myval: 1 }, { myval: 2 }] }
I've tried both
db.coll.update({}, {$unset: {'things.myval': 1}})
and
db.coll.things.update({}, {$unset: {'myval': 1}})
Neither of these work. I can't find any documentation online describing how to do this.
I came across this and was frustrated to see the only was to do this was using a nested forEach. So after some searching I found another way! Since mongo version 3.6 there is a all positional operator ($[]
) (version 3.6 was introduced way after this question was asked... and even after it was last active, BUT incase anyone else comes across this)
To remove the column myval
from the first embedded document to match, do this:
db.coll.update(
{things: {'$exists': true}},
{$unset: {'things.$[].myval': 1}}
)
or if you want to remove it from all document that match use the updateMany
db.coll.updateMany(
{things: {'$exists': true}},
{$unset: {'things.$[].myval': 1}}
)
The $unset
will only edit it if the value exists but it will not do a safe navigation (i.e. it wont check it things exists first) so the exists is needed on the embedded document/array.
You can remove a value from an "array" using the $pull operator:
db.coll.update({}, {$pull: {'things': {'myval': 1}}});
Also have a look at the documentation of $pull:
http://www.mongodb.org/display/DOCS/Updating#Updating-%24pull
Should work with your first approach according with the official documentation:
db.coll.update({}, {$unset: {'things.myval': 1}})
But that doesn't work for me to. So, the solution I found, applied to your example was:
db.coll.find().forEach(function(o) {
for(var i=0; i<o.things.length; i++) {
var unset = {};
unset["things." + i + ".myval"] = "";
db.coll.update( { "_id": o._id }, { "$unset": unset } );
}
})
Or with a more functional style:
db.coll.find().forEach(function(o) {
o.things.forEach(function(t, i) {
var unset = {};
unset["things." + i + ".myval"] = "";
db.coll.update( { "_id": o._id }, { "$unset": unset } );
})
})
It can't work because the {}-empty selector selects more than one documents, and update normally try to update a single document.In order to make it work, use the multi flag to tell mongo update that more than one document is comin.
multi - indicates if all documents matching criteria should be updated rather than just one. Can be useful with the $ operators below.
db.coll.update({}, {$unset: {'things.myval': 1}},false,true)
or
db.coll.update({}, {$pull: {'things': {'myval': 1}}},false,true)
Try either one and will see which one works, but you have to use multi param in both
精彩评论