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

mongodb $addToSet auf ein Feld, das kein Array ist, wenn bei Upsert aktualisiert wird

Was Sie hier versuchen, ist, einem Array nur dort ein neues Element hinzuzufügen, wo das Element nicht vorhanden ist, und auch ein neues Dokument zu erstellen, wo es nicht vorhanden ist. Sie wählen $addToSet weil Sie möchten, dass die Artikel einzigartig sind, aber in Wirklichkeit möchten Sie, dass sie nur durch "a" einzigartig sind.

Also $addToset wird das nicht tun, und Sie müssen eher das vorhandene Element "testen". Aber das eigentliche Problem hier ist, dass es nicht möglich ist, dies gleichzeitig zu tun und zu "upsert". Die Logik kann nicht funktionieren, da immer dann, wenn das Array-Element nicht gefunden wurde, ein neues Dokument erstellt wird, anstatt wie gewünscht an das Array-Element anzuhängen.

Die aktuellen Betriebsfehler sind beabsichtigt als $addToSet kann nicht zum "Erstellen" eines Arrays verwendet werden, sondern nur zum "Hinzufügen" von Elementen zu einem vorhandenen Array. Aber wie bereits erwähnt, haben Sie andere Probleme, die Logik zu erreichen.

Was Sie hier brauchen, ist eine Folge von Aktualisierungsvorgängen, die jeweils "versuchen", ihre erwartete Aktion auszuführen. Dies ist nur mit mehreren Anweisungen möglich:

// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
    { "upsert": true }
)

// $push the element where "a": 1 does not exist
db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 2 } }}
)

// $set the element where "a": 1 does exist
db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 2 } }
)

Bei einer ersten Iteration wird die erste Anweisung das Dokument "aufheben" und das Array mit Elementen erstellen. Die zweite Anweisung stimmt nicht mit dem Dokument überein, da das Element "a" den angegebenen Wert hat. Die dritte Anweisung stimmt mit dem Dokument überein, ändert es aber bei einer Schreiboperation nicht, da sich die Werte nicht geändert haben.

Wenn Sie nun die Eingabe auf "b": 3 ändern Sie erhalten unterschiedliche Antworten, aber das gewünschte Ergebnis:

db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
    { "upsert": true }
)

db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 3 } }}
)

db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 3 } }
)

Die erste Anweisung passt jetzt also auf ein Dokument mit "name": "abc" aber macht nichts, da die einzigen gültigen Operationen auf "insert" sind. Die zweite Anweisung stimmt nicht überein, weil "a" der Bedingung entspricht. Die dritte Anweisung passt den Wert von "a" an und ändert "b" im übereinstimmenden Element auf den gewünschten Wert.

Das nachträgliche Ändern von "a" in einen anderen Wert, der nicht im Array existiert, erlaubt sowohl 1 als auch 3, nichts zu tun, aber die zweite Anweisung fügt dem Array ein weiteres Mitglied hinzu, wobei der Inhalt durch ihre "a"-Schlüssel eindeutig bleibt.

Auch das Einreichen einer Erklärung ohne Änderungen bestehender Daten führt natürlich zu einer Antwort, die besagt, dass an allen Konten nichts geändert wurde.

So führen Sie Ihre Operationen durch. Sie können dies mit "ordered" Bulk tun Vorgänge, sodass es nur eine einzige Anfrage und Antwort vom Server mit der gültigen Antwort auf „modified“ oder „created“ gibt.