Processen här är egentligen ganska enkel, den varierar bara i var du vill "hitta eller skapa" elementen i arrayen.
För det första, förutsatt att elementen för varje nyckel redan finns på plats, är det enkla fallet att fråga efter elementet och uppdatera med indexet som returneras via positional $
operatör:
db.collection.update(
{
"_id": docId,
"attrs": { "$elemMatch": { "key": "A1", "type": "T1" } }
}
{ "$set": { "attrs.$.value": "20" }
)
Det kommer bara att ändra elementet som matchas utan att påverka andra.
I det andra fallet där "hitta eller skapa" krävs och den specifika nyckeln kanske inte existerar, använder du "två" uppdateringssatser. Men Bulk Operations API låter dig göra detta i en enda begäran till servern med ett enda svar:
var bulk = db.collection.initializeOrderedBulkOp();
// Try to update where exists
bulk.find({
"_id": docId,
"attrs": { "$elemMatch": { "key": "A1", "type": "T2" } }
}).updateOne({
"$set": { "attrs.$.value": "30" }
});
// Try to add where does noes not exist
bulk.find({
"_id": docId,
"attrs": { "$not": { "$elemMatch": { "key": "A1", "type": "T2" } } }
}).updateOne({
"$push": { "attrs": { "key": "A1", "type": "T2", "value": "30" } }
});
bulk.execute();
Den grundläggande logiken är att först görs uppdateringsförsöket för att matcha ett element med de nödvändiga värdena precis som tidigare. Det andra tillståndet testar var elementet inte hittas alls genom att vända matchningslogiken med $not
.
I det fall där arrayelementet inte hittades är ett nytt giltigt för tillägg via $push
.
Jag bör verkligen tillägga att eftersom vi specifikt letar efter negativa matchningar här är det alltid en bra idé att matcha "dokumentet" som du tänker uppdatera med någon unik identifierare såsom _id
nyckel. Även om det är möjligt med "multi"-uppdateringar, måste du vara försiktig med vad du gör.
Så i fallet med att köra "hitta eller skapa"-processen så läggs element som inte matchades till arrayen korrekt, utan att störa andra element, även den tidigare uppdateringen för en förväntad matchning tillämpas på samma sätt:
{
"_id" : ObjectId("55b570f339db998cde23369d"),
"attrs" : [
{
"key" : "A1",
"type" : "T1",
"value" : "20"
},
{
"key" : "A2",
"type" : "T2",
"value" : "14"
},
{
"key" : "A1",
"type" : "T2",
"value" : "30"
}
]
}
Detta är ett enkelt mönster att följa, och naturligtvis tar Bulk Operations här bort alla inblandade overhead genom att skicka och ta emot flera förfrågningar till och från servern. Allt detta fungerar lyckligtvis utan att störa andra element som kanske existerar eller inte.
Bortsett från det finns det extra fördelar med att hålla data i en array för enkel sökning och analys som stöds av standardoperatörerna utan att behöva återgå till JavaScript-serverbearbetning för att gå igenom elementen.