Nein, es ist nicht wirklich eine bessere Lösung, also vielleicht mit einer Erklärung.
Angenommen, Sie ein Dokument an der richtigen Stelle, die die Struktur hat, wie Sie zeigen:
{
"name": "foo",
"bars": [{
"name": "qux",
"somefield": 1
}]
}
Wenn Sie das tun ein Update wie dieses
db.foo.update(
{ "name": "foo", "bars.name": "qux" },
{ "$set": { "bars.$.somefield": 2 } },
{ "upsert": true }
)
Dann alles, weil passende Dokument in Ordnung war gefunden. Aber wenn Sie den Wert von "bars.name" ändern:
Dann erhalten Sie einen Fehler. Das einzige, was hier wirklich geändert hat, ist, dass in MongoDB 2.6 und über dem Fehler etwas prägnanter ist:
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"
}
})
, die besser in gewisser Weise, aber Sie wollen wirklich nicht sowieso „Upsert“. Was Sie tun möchten, ist das Element zu dem Array hinzufügen, wo der "Name" derzeit nicht existiert.
Also, was Sie wirklich wollen, ist das „Ergebnis“ aus dem Update-Versuch ohne die „Upsert“ Flagge zu sehen, ob irgendwelche Dokumente betroffen waren:
db.foo.update(
{ "name": "foo", "bars.name": "xyz" },
{ "$set": { "bars.$.somefield": 2 } }
)
in Reaktion Nachgeben:
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
Also, wenn die geänderten Dokumente sind 0
dann wissen Sie, Sie das folgende Update ausgegeben werden soll:
db.foo.update(
{ "name": "foo" },
{ "$push": { "bars": {
"name": "xyz",
"somefield": 2
}}
)
Es gibt wirklich keinen anderen Weg, genau das zu tun, was Sie wollen. Da es sich bei den Hinzufügungen zum Array nicht unbedingt um einen Operationstyp "set" handelt, können Sie $addToSet
in Kombination mit der "bulk update"-Funktionalität nicht verwenden, sodass Sie Ihre Aktualisierungsanforderungen "kaskadieren" können.
In diesem Fall scheint es, als ob Sie das Ergebnis überprüfen müssen, oder andernfalls akzeptieren Sie das Lesen des gesamten Dokuments und überprüfen, ob ein neues Array-Element im Code zu aktualisieren oder einzufügen.
Ja, das ist, was ich gerade habe - '$ set', gefolgt von einem' $ push', wenn keine passenden Dokumente gefunden wurden ... Ich habe mich nur gefragt, ob es einen besseren Weg gibt. Danke für die Erklärung! – shesek
Wie machen Sie das atomar, wenn Sie mehrere Prozesse gleichzeitig versuchen zu aktualisieren. Scheint so, als könnte es eine Race Condition geben und du könntest $ push mehr als einmal aufrufen und am Ende mehr als einen Record im Array haben. Gibt es eine Möglichkeit, den neuen Wert auf atomare Weise einzufügen? –
@MichaelMoser Nur gerade den Kommentar gesehen. Aber indem Sie einen Ungleichungstest wie '{" name ":" foo "," bars.name ": {" $ ne ":" xyz "}}' als Abfrage hinzufügen, stellen Sie sicher, dass Sie keine "gepushten" Elemente duplizieren . –