Upsert, който води до вмъкване на документ, не е напълно атомарна операция. Мислете за upsert като за изпълнение на следните дискретни стъпки:
- Запитване за идентифицирания документ, който да бъде поставен.
- Ако документът съществува, атомарно актуализирайте съществуващия документ.
- В противен случай (документът не съществува), атомарно вмъкнете нов документ, който включва полетата на заявката и актуализацията.
Така че стъпки 2 и 3 са атомарни, но може да възникне друг upsert след стъпка 1, така че вашият код трябва да провери за грешка с дублиран ключ и след това да опита отново upsert, ако това се случи. В този момент знаете документа с този _id
съществува, така че винаги ще успее.
Например:
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);
}
}
});
Вижте тук свързаната документация.
Може би все още се чудите защо това може да се случи, ако вмъкването е атомарно, но това означава, че няма да има актуализации на вмъкнатия документ, докато не бъде напълно написан, а не че няма друго вмъкване на документ със същия _id
може да се случи.
Освен това не е необходимо да създавате ръчно индекс на _id
тъй като всички колекции на MongoDB имат уникален индекс на _id
независимо. Така че можете да премахнете този ред:
monitorSchema.index({_id: -1}); // Not needed