MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

mongodb $addToSet in un campo non array quando si aggiorna all'upsert

Quello che stai cercando di fare qui è aggiungere un nuovo elemento a un array solo dove l'elemento non esiste e anche creare un nuovo documento dove non esiste. Scegli $addToSet perché vuoi che gli articoli siano unici, ma in realtà vuoi che siano unici solo per "a".

Quindi $addToset non lo farà, e devi piuttosto "testare" l'elemento presente. Ma il vero problema qui è che non è possibile farlo e "rimontare" allo stesso tempo. La logica non può funzionare poiché un nuovo documento verrà creato ogni volta che l'elemento dell'array non è stato trovato, invece di aggiungerlo all'elemento dell'array come si desidera.

Gli errori operativi correnti in base alla progettazione come $addToSet non può essere utilizzato per "creare" una matrice, ma solo per "aggiungere" membri a una matrice esistente. Ma come già affermato, hai altri problemi con il raggiungimento della logica.

Ciò di cui hai bisogno qui è una sequenza di operazioni di aggiornamento che ciascuna "tenta" di eseguire l'azione prevista. Questo può essere fatto solo con più istruzioni:

// 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 } }
)

In una prima iterazione, la prima istruzione "aggiornerà" il documento e creerà l'array con gli elementi. La seconda istruzione non corrisponderà al documento perché l'elemento "a" ha il valore specificato. La terza istruzione corrisponderà al documento ma non lo altererà in un'operazione di scrittura perché i valori non sono cambiati.

Se ora modifichi l'input in "b": 3 ottieni risposte diverse ma il risultato desiderato:

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 } }
)

Quindi ora la prima istruzione corrisponde a un documento con "name": "abc" ma non fa nulla poiché le uniche operazioni valide sono su "insert". La seconda istruzione non corrisponde perché "a" soddisfa la condizione. La terza affermazione corrisponde al valore di "a" e cambia "b" nell'elemento abbinato al valore desiderato.

Successivamente la modifica di "a" in un altro valore che non esiste nell'array consente a 1 e 3 di non fare nulla, ma la seconda istruzione aggiunge un altro membro all'array mantenendo il contenuto univoco tramite le loro chiavi "a".

Anche l'invio di una dichiarazione senza modifiche rispetto ai dati esistenti comporterà ovviamente una risposta che dice che non viene modificato nulla su tutti gli account.

È così che fai le tue operazioni. Puoi farlo con "ordinato" In blocco operazioni in modo che ci sia una sola richiesta e risposta dal server con la risposta valida modificata o creata.