Io e i miei colleghi abbiamo trovato una soluzione alternativa. Possiamo chiamarla inizializzazione in tre passaggi .
Ricorda che MongoDB garantisce l'atomicità delle operazioni su un singolo documento. Tenendo presente questo fatto possiamo operare nel modo seguente:
- Prova ad aggiornare il documento, incrementando opportunamente i contatori ad un determinato intervallo di tempo. Non eseguire alcun upsert, solo un'operazione di aggiornamento vecchio stile. Ricorda che l'esecuzione di una dichiarazione di aggiornamento restituisce il numero di documenti scritti. Se il numero di documenti scritti è maggiore di zero, hai finito.
- Se il numero di documenti scritti dall'aggiornamento è zero, significa che il relativo documento da aggiornare non è ancora presente nella raccolta. Prova a inserire l'intero documento per i tag specificati. Metti tutti i contatori (valori di campo) a zero. Anche l'esecuzione di un'istruzione insert restituisce il numero di documenti scritti. Se restituisce zero o genera un'eccezione, non importa:significa che qualche altro processo aveva già inserito il documento per gli stessi tag.
- Esegui di nuovo lo stesso aggiornamento precedente.
Il codice dovrebbe essere simile al seguente snippet di codice.
// Firt of all, try the update
var result = db.test.update(
{timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"), type: “memory_used”},
{$inc: {"values.39": 1}},
{upsert: false}
);
// If the update do not succeed, then try to insert the document
if (result.nModified === 0) {
try {
db.test.insert(/* Put here the whole document */);
} catch (err) {
console.log(err);
}
// Here we are sure that the document exists.
// Retry to execute the update statement
db.test.update(/* Same update as above */);
}
La procedura precedente funziona se è valida una precondizione:_id
il valore deve essere derivato da altri campi nel documento. Nel nostro esempio, _id
il valore sarebbe '2013-10-10T23:06:00.000Z-memory_used
. Solo utilizzando questa tecnica, l'inserto al punto 2. fallirà correttamente.