En upsert, der resulterer i en dokumentindsættelse, er ikke en fuldstændig atomart operation. Tænk på upsert som at udføre følgende diskrete trin:
- Forespørgsel om, at det identificerede dokument skal ophæves.
- Hvis dokumentet eksisterer, skal du atomisk opdatere det eksisterende dokument.
- Ellers (dokumentet findes ikke), indsæt atomisk et nyt dokument, der inkorporerer forespørgselsfelterne og opdateringen.
Så trin 2 og 3 er hver atomare, men en anden upsert kan forekomme efter trin 1, så din kode skal tjekke for duplikatnøglefejlen og derefter prøve upsert igen, hvis det sker. På det tidspunkt kender du dokumentet med det _id
eksisterer, så det vil altid lykkes.
For eksempel:
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);
}
}
});
Se her for den relaterede dokumentation.
Du undrer dig måske stadig over, hvorfor dette kan ske, hvis indsættelsen er atomær, men det betyder, at der ikke vil ske opdateringer på det indsatte dokument, før det er fuldstændigt skrevet, ikke at der ikke er nogen anden indsættelse af et dokument med samme _id
kan forekomme.
Du behøver heller ikke manuelt at oprette et indeks på _id
da alle MongoDB-samlinger har et unikt indeks på _id
uanset. Så du kan fjerne denne linje:
monitorSchema.index({_id: -1}); // Not needed