Nie, nie ma lepszego rozwiązania tego problemu, więc może z wyjaśnieniem.
Załóżmy, że masz dokument o pokazanej strukturze:
{
"name": "foo",
"bars": [{
"name": "qux",
"somefield": 1
}]
}
Jeśli dokonasz takiej aktualizacji
db.foo.update(
{ "name": "foo", "bars.name": "qux" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Wtedy wszystko jest w porządku, ponieważ znaleziono pasujący dokument. Ale jeśli zmienisz wartość „bars.name”:
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Wtedy dostaniesz porażkę. Jedyną rzeczą, która naprawdę się tutaj zmieniła, jest to, że w MongoDB 2.6 i nowszych błąd jest trochę bardziej zwięzły:
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"
}
})
Pod pewnymi względami jest to lepsze, ale i tak naprawdę nie chcesz się „zwracać”. To, co chcesz zrobić, to dodać element do tablicy, w której „nazwa” obecnie nie istnieje.
Więc to, czego naprawdę chcesz, to „wynik” próby aktualizacji bez flagi „upsert”, aby sprawdzić, czy jakikolwiek dokument został naruszony:
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } }
)
Ustępowanie w odpowiedzi:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
Więc kiedy zmodyfikowane dokumenty mają wartość 0
to wiesz, że chcesz wydać następującą aktualizację:
db.foo.update(
{ "name": "foo" },
{ "$push": { "bars": {
"name": "xyz",
"somefield": 2
}}
)
Naprawdę nie ma innego sposobu na zrobienie dokładnie tego, czego chcesz. Ponieważ dodatki do tablicy nie są ściśle "ustawianym" typem operacji, nie można użyć $addToSet
w połączeniu z funkcją „zbiorczej aktualizacji”, dzięki czemu można „kaskadowo” przesyłać żądania aktualizacji.
W tym przypadku wydaje się, że musisz sprawdzić wynik lub w inny sposób zaakceptować odczytanie całego dokumentu i sprawdzenie, czy zaktualizować lub wstawić nowy element tablicy w kodzie.