Ich und meine Kollegen haben eine Problemumgehung gefunden. Wir können es dreistufige Initialisierung nennen .
Denken Sie daran, dass MongoDB die Unteilbarkeit von Operationen für ein einzelnes Dokument garantiert. Unter Berücksichtigung dieser Tatsache können wir folgendermaßen vorgehen:
- Versuchen Sie, das Dokument zu aktualisieren, indem Sie die Zähler zu einem bestimmten Zeitabschnitt richtig erhöhen. Führen Sie kein Upsert durch, nur eine altmodische Aktualisierungsoperation. Denken Sie daran, dass die Ausführung einer Update-Anweisung die Anzahl der geschriebenen Dokumente zurückgibt. Wenn die Anzahl der geschriebenen Dokumente größer als null ist, sind Sie fertig.
- Wenn die Anzahl der durch die Aktualisierung geschriebenen Dokumente Null ist, bedeutet dies, dass das entsprechende zu aktualisierende Dokument noch nicht in der Sammlung vorhanden ist. Versuchen Sie, das gesamte Dokument für die angegebenen Tags einzufügen. Setzen Sie alle Zähler (Feldwerte) auf Null. Auch die Ausführung einer Insert-Anweisung gibt die Anzahl der geschriebenen Dokumente zurück. Wenn es Null zurückgibt oder eine Ausnahme auslöst, egal:Das bedeutet, dass ein anderer Prozess das Dokument bereits für dieselben Tags eingefügt hat.
- Führen Sie dasselbe obige Update noch einmal durch.
Der Code sollte dem folgenden Code-Snippet ähneln.
// 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 */);
}
Das obige Verfahren funktioniert, wenn eine Vorbedingung erfüllt ist:_id
Der Wert sollte von anderen Feldern im Dokument abgeleitet werden. In unserem Beispiel _id
Wert wäre '2013-10-10T23:06:00.000Z-memory_used
. Nur mit dieser Technik wird der Einsatz an Punkt 2. ordnungsgemäß fehlschlagen.