Nej, det finns egentligen ingen bättre lösning på detta, så kanske med en förklaring.
Anta att du har ett dokument på plats som har strukturen som du visar:
{
"name": "foo",
"bars": [{
"name": "qux",
"somefield": 1
}]
}
Om du gör en sådan här uppdatering
db.foo.update(
{ "name": "foo", "bars.name": "qux" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Då är allt bra eftersom matchande dokument hittades. Men om du ändrar värdet på "bars.name":
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Då får du ett misslyckande. Det enda som verkligen har förändrats här är att i MongoDB 2.6 och uppåt är felet lite mer kortfattat:
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 16836,
"errmsg" : "The positional operator did not find the match needed from the query. Unexpanded update: bars.$.somefield"
}
})
Det är bättre på vissa sätt, men du vill verkligen inte "uppröra" ändå. Vad du vill göra är att lägga till elementet i arrayen där "namnet" inte finns för närvarande.
Så vad du verkligen vill ha är "resultatet" från uppdateringsförsöket utan flaggan "upsert" för att se om några dokument påverkades:
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } }
)
Ge efter som svar:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
Så när de ändrade dokumenten är 0
då vet du att du vill utfärda följande uppdatering:
db.foo.update(
{ "name": "foo" },
{ "$push": { "bars": {
"name": "xyz",
"somefield": 2
}}
)
Det finns verkligen inget annat sätt att göra precis vad du vill. Eftersom tilläggen till arrayen inte strikt är en "set"-typ av operation, kan du inte använda $addToSet
kombinerat med funktionen "bulkuppdatering" där, så att du kan "kaskadera" dina uppdateringsförfrågningar.
I det här fallet verkar det som om du måste kontrollera resultatet, eller på annat sätt acceptera att läsa hela dokumentet och kontrollera om du ska uppdatera eller infoga ett nytt arrayelement i koden.