ドキュメント挿入をもたらすアップサートは、完全に不可分操作ではありません。アップサートは、次の個別の手順を実行するものと考えてください。
- アップサートする識別されたドキュメントを照会します。
- ドキュメントが存在する場合は、既存のドキュメントをアトミックに更新します。
- それ以外の場合(ドキュメントは存在しません)、クエリフィールドと更新を組み込んだ新しいドキュメントをアトミックに挿入します。
したがって、ステップ2と3はそれぞれアトミックですが、ステップ1の後に別のアップサートが発生する可能性があるため、コードで重複キーエラーをチェックし、発生した場合はアップサートを再試行する必要があります。その時点で、その_id
を持つドキュメントがわかります。 存在するので、常に成功します。
例:
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);
}
}
});
関連するドキュメントについては、こちらをご覧ください。
挿入がアトミックである場合になぜこれが発生するのか疑問に思うかもしれませんが、それは、挿入されたドキュメントが完全に書き込まれるまで更新が行われないことを意味し、同じ_id
発生する可能性があります。
また、_id
に手動でインデックスを作成する必要はありません。 すべてのMongoDBコレクションには_id
に一意のインデックスがあるため 関係なく。したがって、次の行を削除できます:
monitorSchema.index({_id: -1}); // Not needed