Аз и моите колеги намерихме заобиколно решение. Можем да го наречем инициализация в три стъпки .
Не забравяйте, че MongoDB гарантира атомарността на операциите върху един документ. Имайки предвид този факт, можем да работим по следния начин:
- Опитайте се да актуализирате документа, като увеличите правилно броячите в определена времева част. Не правете никакви upsert, просто старомодна операция за актуализиране. Не забравяйте, че изпълнението на оператор за актуализиране връща броя на написаните документи. Ако броят на написаните документи е по-голям от нула, сте готови.
- Ако броят документи, записани от актуализацията, е нула, тогава това означава, че съответният документ за актуализация все още не присъства в колекцията. Опитайте се да вмъкнете целия документ за посочените тагове. Поставете всички броячи (стойности на полета) на нула. Също така изпълнението на оператор за вмъкване връща броя на написаните документи. Ако върне нула или хвърли изключение, няма значение:това означава, че някой друг процес вече е вмъкнал документа за същите тагове.
- Изпълнете същата горна актуализация отново.
Кодът трябва да изглежда като нещо подобно на следния кодов фрагмент.
// 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 */);
}
Горната процедура работи, ако е изпълнено предварително условие:_id
стойността трябва да бъде извлечена от други полета в документа. В нашия пример, _id
стойността ще бъде '2013-10-10T23:06:00.000Z-memory_used
. Само при използване на тази техника, вложката в точка 2. ще се провали правилно.