Upsert, jehož výsledkem je vložení dokumentu, není plně atomická operace. Představte si, že upsert provádí následující samostatné kroky:
- Dotaz na identifikovaný dokument, který má být aktualizován.
- Pokud dokument existuje, atomicky aktualizujte existující dokument.
- Jinak (dokument neexistuje), atomicky vložte nový dokument, který obsahuje pole dotazu a aktualizaci.
Kroky 2 a 3 jsou tedy atomické, ale po kroku 1 může dojít k dalšímu upsert, takže váš kód musí zkontrolovat chybu duplicitního klíče a poté opakovat upsert, pokud k tomu dojde. V tu chvíli znáte dokument s tímto _id
existuje, takže vždy uspěje.
Například:
var minute = utils.minute();
Monitor.update({ _id: minute }, { $inc: update }, { upsert: true }, function(err) {
if (err) {
if (err.code === 11000) {
// Another upsert occurred during the upsert, try again. You could omit the
// upsert option here if you don't ever delete docs while this is running.
Monitor.update({ _id: minute }, { $inc: update }, { upsert: true },
function(err) {
if (err) {
console.trace(err);
}
});
}
else {
console.trace(err);
}
}
});
Zde naleznete související dokumentaci.
Možná se stále ptáte, proč se to může stát, pokud je vložka atomická, ale to znamená, že ve vloženém dokumentu nedojde k žádným aktualizacím, dokud nebude zcela napsán, nikoli že žádná jiná vložka dokumentu se stejným _id
může dojít.
Také nemusíte ručně vytvářet index na _id
protože všechny kolekce MongoDB mají jedinečný index na _id
bez ohledu na. Takže můžete odstranit tento řádek:
monitorSchema.index({_id: -1}); // Not needed