REDIGERA
Detaljen som saknades i frågan var att det obligatoriska fältet att uppdatera faktiskt fanns i ett underdokument . Detta ändrar svaret avsevärt:
Detta är en begränsning av vad du kan möjligen göra med att uppdatera arrayelement. Och detta förklaras tydligt i dokumentationen . Mest i det här stycket:
Så här är grejen. Försöker uppdatera alla av arrayelementen i en enstaka sats som denna inte arbete. För att göra detta måste du göra följande.
db.warehouses.find({ "items.qty": { "$gt": 0 } }).forEach(function(doc) {
doc.items.forEach(function(item) {
item.qty = 0;
});
db.warehouses.update({ "_id": doc._id }, doc );
})
Vilket i princip är sättet att uppdatera varje arrayelement.
multi inställning i .update()
betyder över flera "dokument". Det kan inte tillämpas på flera element i en array. Så för närvarande är det bästa alternativet att byta ut det hela. Eller i det här fallet kan vi lika gärna byta ut hela dokument eftersom vi måste göra det ändå.
För riktigt massdata, använd db.eval() . Men läs dokumentationen först:
db.eval(function() {
db.warehouses.find({ "items.qty": { "$gt": 0 } }).forEach(function(doc) {
doc.items.forEach(function(item) {
item.qty = 0;
});
db.warehouses.update({ "_id": doc._id }, doc );
});
})
Uppdaterar alla elementen i en array tvärs över helheten samlingen är inte enkel.
Original
Ungefär exakt vad felet säger. För att kunna använda en positionsoperator måste du matcha något först. Som i:
db.warehouses.update(
// query
{
_id:ObjectId('5322f07e139cdd7e31178b78'),
"items.qty": { "$gt": 0 }
},
// update
{
$set:{"items.$.qty":0}
},
// options
{
"multi" : true,
"upsert" : true
}
);
Så där matchen skick fenor positionen av objekten som är mindre än 0 sedan det indexet skickas till positionsoperatören.
P.S :När muti är sant det betyder att den uppdateras varje dokumentera. Lämna det false
om du bara menar en . Vilket är standard.