Il processo qui è davvero abbastanza semplice, varia solo nel punto in cui vuoi "trovare o creare" gli elementi nell'array.
Innanzitutto, supponendo che gli elementi per ciascuna chiave siano già presenti, il caso semplice è interrogare l'elemento e aggiornarlo con l'indice restituito tramite posizionale $
operatore:
db.collection.update(
{
"_id": docId,
"attrs": { "$elemMatch": { "key": "A1", "type": "T1" } }
}
{ "$set": { "attrs.$.value": "20" }
)
Ciò modificherà solo l'elemento corrispondente senza influire sugli altri.
Nel secondo caso in cui è richiesto "trova o crea" e la chiave particolare potrebbe non esistere, si utilizzano "due" istruzioni di aggiornamento. Ma l'API per le operazioni in blocco ti consente di farlo in un'unica richiesta al server con un'unica risposta:
var bulk = db.collection.initializeOrderedBulkOp();
// Try to update where exists
bulk.find({
"_id": docId,
"attrs": { "$elemMatch": { "key": "A1", "type": "T2" } }
}).updateOne({
"$set": { "attrs.$.value": "30" }
});
// Try to add where does noes not exist
bulk.find({
"_id": docId,
"attrs": { "$not": { "$elemMatch": { "key": "A1", "type": "T2" } } }
}).updateOne({
"$push": { "attrs": { "key": "A1", "type": "T2", "value": "30" } }
});
bulk.execute();
La logica di base è che prima viene effettuato il tentativo di aggiornamento per abbinare un elemento con i valori richiesti proprio come fatto prima. L'altra condizione verifica dove l'elemento non viene trovato affatto invertendo la logica di corrispondenza con $not
.
Nel caso in cui l'elemento dell'array non sia stato trovato, uno nuovo è valido per l'aggiunta tramite $push
.
Dovrei davvero aggiungere che poiché stiamo cercando specificamente corrispondenze negative qui, è sempre una buona idea abbinare il "documento" che intendi aggiornare con un identificatore univoco come _id
chiave. Sebbene sia possibile con gli aggiornamenti "multipli", devi stare attento a ciò che stai facendo.
Quindi nel caso di esecuzione del processo "trova o crea" l'elemento che non è stato abbinato viene aggiunto correttamente all'array, senza interferire con altri elementi, anche l'aggiornamento precedente per una corrispondenza attesa viene applicato allo stesso modo:
{
"_id" : ObjectId("55b570f339db998cde23369d"),
"attrs" : [
{
"key" : "A1",
"type" : "T1",
"value" : "20"
},
{
"key" : "A2",
"type" : "T2",
"value" : "14"
},
{
"key" : "A1",
"type" : "T2",
"value" : "30"
}
]
}
Questo è uno schema semplice da seguire e, naturalmente, le operazioni in blocco qui rimuovono qualsiasi sovraccarico coinvolto inviando e ricevendo più richieste da e verso il server. Tutto questo fortunatamente funziona senza interferire con altri elementi che possono esistere o meno.
A parte questo, ci sono gli ulteriori vantaggi di mantenere i dati in un array per una facile query e analisi come supportato dagli operatori standard senza la necessità di ripristinare l'elaborazione del server JavaScript per attraversare gli elementi.