私と私の同僚は回避策を見つけました。これを3ステップの初期化と呼ぶことができます 。
MongoDBは、単一のドキュメントに対する操作の原子性を保証することを忘れないでください。この事実を念頭に置いて、次のように操作できます。
- 指定された時間チャンクでカウンターを適切にインクリメントして、ドキュメントを更新してみてください。アップサートは行わないでください。昔ながらの更新操作だけです。 updateステートメントを実行すると、書き込まれたドキュメントの数が返されることに注意してください。書き込まれたドキュメントの数がゼロより大きい場合は、これで完了です。
- 更新によって書き込まれたドキュメントの数がゼロの場合、更新する相対ドキュメントがコレクションにまだ存在していないことを意味します。指定されたタグのドキュメント全体を挿入してみてください。すべてのカウンター(フィールド値)をゼロにします。また、挿入ステートメントを実行すると、書き込まれたドキュメントの数が返されます。ゼロを返したり、例外をスローしたりしても、気にしないでください。他のプロセスが同じタグのドキュメントをすでに挿入していることを意味します。
- 上記と同じ更新を再度実行します。
コードは、次のコードスニペットのようになります。
// 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の挿入は適切に失敗します。