Upsert, który skutkuje wstawieniem dokumentu, nie jest operacją w pełni niepodzielną. Pomyśl o upsert jako wykonując następujące dyskretne kroki:
- Zapytanie o wskazany dokument do wstawienia.
- Jeśli dokument istnieje, zaktualizuj go atomowo.
- W przeciwnym razie (dokument nie istnieje), niepodzielnie wstaw nowy dokument, który zawiera pola zapytania i aktualizację.
Tak więc kroki 2 i 3 są niepodzielne, ale po kroku 1 może wystąpić kolejne upsert, więc kod musi sprawdzić błąd zduplikowanego klucza, a następnie ponowić upsert, jeśli wystąpi. W tym momencie znasz dokument z tym _id
istnieje, więc zawsze się powiedzie.
Na przykład:
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);
}
}
});
Zobacz tutaj powiązaną dokumentację.
Nadal możesz się zastanawiać, dlaczego tak się dzieje, jeśli wstawka jest niepodzielna, ale oznacza to, że żadne aktualizacje nie nastąpią we wstawionym dokumencie, dopóki nie zostanie całkowicie napisany, a nie, że żadna inna wstawka dokumentu z tym samym
Ponadto nie musisz ręcznie tworzyć indeksu na _id
ponieważ wszystkie kolekcje MongoDB mają unikalny indeks na _id
bez względu. Możesz więc usunąć tę linię:
monitorSchema.index({_id: -1}); // Not needed