Sie waren ein Teil des Weges dorthin, indem Sie die erforderlichen Operationen richtig identifiziert haben. Aber natürlich $sort
ist kein gültiger Modifikator für $addToSet
denn das MongoDB-Mantra lautet "Sätze gelten nicht als bestellt" :
Das andere Problem hier, wie der Fehler anzeigt, besteht darin, dass Sie nicht mehrere Aktualisierungsoperatoren verwenden können (wie z. B. $addToSet
und $push
) gleichzeitig auf demselben Pfad zu einer Eigenschaft. Es gibt tatsächlich "keine Reihenfolge" für die Ausführung verschiedener Aktualisierungsoperatoren, daher gibt es keine Garantie dafür, dass $addToSet
tritt vor dem $push
auf . Tatsächlich agieren sie wahrscheinlich parallel, weshalb der Fehler auftritt und dass dies nicht zulässig ist.
Die Antwort lautet natürlich „zwei“ Update-Anweisungen. Eine für $addToSet
und eine, um den $sort
anzuwenden durch "Pushen" eines leeren Arrays über $each
,
Aber da wir wirklich nicht auf den Abschluss jeder Aktualisierung „warten“ wollen, ist die „Bulk“-Operations-API genau dafür da. So können Sie beide Anweisungen in einem an den Server senden senden und einen erhalten Antwort:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({ "name": "Risas" }).update({
"$addToSet": {
"propiedades": { "name": "cola", "cantidad": 1 }
}
});
bulk.find({ "name": "Risas" }).update({
"$push": {
"propiedades": {
"$each": [ ], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Das ist also wirklich immer noch nur eine Anfrage an den Server und eine Antwort. Es sind immer noch "zwei" Operationen, aber der Overhead und die Möglichkeit, dass ein Thread den Zwischenzustand der Aktualisierung erfasst, ist vernachlässigbar.
Es gibt eine Alternative zu diesem Ansatz, die darin besteht, die Logik "Festlegen der Erkennung" in .find()
zu verschieben Teil der Update-Anweisung und wenden Sie dann einfach $push
an wobei die Mitglieder, die dem "Satz" hinzugefügt werden sollen, noch nicht existieren:
var bulk = db.perros.initializeOrderedBulkOp();
bulk.find({
"name": "Risas",
"propiedades": {
"$not": { "$elemMatch": { "name": "cola", "cantidad": 1 } }
}
}).update({
"$push": {
"propiedades": {
"$each": [{ "name": "cola", "cantidad": 1 }], "$sort": { "cantidad": -1 }
}
}
});
bulk.execute();
Die Komplikation besteht natürlich darin, dass Sie, wenn Sie hier "mehrere" Array-Elemente hinzufügen, diese $not
und $elemMacth
Tests in einem $and
Bedingung, und wenn "nur eines" dieser Elemente gültig war, konnte es nicht alleine hinzugefügt werden.
Sie können diese Art von Operation "zuerst" mit "mehreren" Elementen "versuchen", aber dann sollten Sie es haben eine "Fallback"-Ausführung jedes einzelnen Array-Elements mit der gleichen Logik wie oben, um die Möglichkeit des "Pushens" für jedes einzelne zu "testen".
Also $addToSet
macht diesen zweiten Teil mit mehreren Array-Einträgen einfach. Für einen Eintrag ist es ganz einfach, nur "abzufragen" und $push
, für mehr als einen ist es wahrscheinlich der kürzere Weg, das "erste" Muster mit $addToSet
zu verwenden und $push
ein leeres Array, um das Ergebnis zu "sortieren", da die Anwendung des zweiten Musters ohnehin mehrere Aktualisierungstests bedeutet.