MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Wie kann ich mit MongoDB ein Objekt $addToSet zu einem Array hinzufügen und $sortieren?

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.