MongoDBでは、複数の値を変更する場合でも、書込み操作は単一ドキュメント レベルで アトミックです。並列更新の場合、各 コマンドはクエリ条件が引き続き一致することを確認します。
同時更新中の競合を防ぐには、更新フィルターに現在予想されている値を含めます。
ユースケース
このドキュメントを含むコレクションについて考えてみます。
db.games.insertOne( { _id: 1, score: 80 } )
これらの更新操作は同時に発生します。
// Update A db.games.updateOne( { score: 80 }, { $set: { score: 90 } } ) // Update B db.games.updateOne( { score: 80 }, { $set: { score: 100 } } )
1 回の更新により、score は 90 または 100 に設定されます。その後、2 番目の更新は { score: 80 } と一致するように失敗し、実行されません。
警告
更新していないフィールドをフィルタリングすると、同時更新中に予期しない結果を引き起こすことがあります。次の操作を検討してください。
// Update A db.games.updateOne( { _id: 1 }, { $set: { score: 90 } } ) // Update B db.games.updateOne( { _id: 1 }, { $set: { score: 100 } } )
どちらのアップデートも { _id: 1 } と一致するため、両方が実行されます。 2 番目の更新は 1 番目の更新を上書きします。最初のクライアントは、更新が失われたことを示す警告を受け取りません。
更新されていないフィールドをフィルタリングするときに競合を回避するには、$inc を使用します。
を例として、次の同時更新操作について考えてみましょう。
// Update A db.games.updateOne( { _id: 1 }, { $inc: { score: 10 } } ) // Update B db.games.updateOne( { _id: 1 }, { $inc: { score: 20 } } )
どちらのアップデートも { _id: 1 } と一致します。値を設定するのではなく、増加するため、互いに上書きされることはありません。最後の score は 110 です。
Tip
Store Unique Values
一意性を強制するには、ユニークインデックスを作成します。これにより、挿入や更新における重複データを防止できます。複数のフィールドに一意のインデックスを作成することもできます。 「 単一フィールド一意のインデックスの作成 」を参照してください。
詳細
このセクションでは、マルチドキュメントトランザクションに関する追加の詳細について説明します。
単一の書込み操作(例: db.collection.updateMany())は複数のドキュメントを変更します。各ドキュメントの変更は不可分ですが、操作全体は不可分ではありません。
複数のドキュメントへの書込み操作を実行する場合、1 回の書込み操作でも複数の書込み操作でも、他の操作がインターリーブすることがあります。
MongoDB は(単一または複数のコレクション内の)複数のドキュメントへの読み取りと書込みにアトミック性を必要とする状況で、レプリカセットやシャーディングされたクラスターでのトランザクションを含む分散トランザクションをサポートします。
詳細については、「トランザクション」を参照してください。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。