Ja i moi koledzy znaleźliśmy obejście. Możemy to nazwać inicjalizacją w trzech krokach .
Pamiętaj, że MongoDB gwarantuje niepodzielność operacji na pojedynczym dokumencie. Mając to na uwadze, możemy działać w następujący sposób:
- Spróbuj zaktualizować dokument, prawidłowo zwiększając liczniki w określonym czasie. Nie rób żadnych upsert, tylko staromodna operacja aktualizacji. Pamiętaj, że wykonanie oświadczenia aktualizującego zwraca liczbę napisanych dokumentów. Jeśli liczba napisanych dokumentów jest większa niż zero, gotowe.
- Jeśli liczba dokumentów zapisanych przez aktualizację wynosi zero, oznacza to, że odpowiedni dokument do aktualizacji nie znajduje się jeszcze w kolekcji. Spróbuj wstawić cały dokument dla określonych tagów. Ustaw wszystkie liczniki (wartości pól) na zero. Również wykonanie instrukcji insert zwraca liczbę napisanych dokumentów. Jeśli zwraca zero lub zgłasza wyjątek, nieważne:oznacza to, że jakiś inny proces wstawił już dokument dla tych samych znaczników.
- Przeprowadź tę samą powyższą aktualizację ponownie.
Kod powinien wyglądać podobnie do poniższego fragmentu kodu.
// 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 */);
}
Powyższa procedura działa, jeśli warunek wstępny jest spełniony:_id
wartość powinna pochodzić z innych pól w dokumencie. W naszym przykładzie _id
wartość to '2013-10-10T23:06:00.000Z-memory_used
. Tylko przy użyciu tej techniki wstawka w punkcie 2. nie powiedzie się.