db.collection.bulkWrite()
MongoDB とドライバー
このページでは、 mongosh
メソッドについて説明します。MongoDB ドライバーで同等のメソッドを確認するには、ご使用のプログラミング言語の対応するページを参照してください。
定義
db.collection.bulkWrite()
実行順序の制御を使用して複数の書き込み操作を実行します。
次の値を返します。 - ブール値は、 書込み保証(write concern)が有効化されて操作が実行された場合は
true
として、無効化されていた場合はfalse
としてacknowledged
されます。 - 各書き込み操作のカウント。
- 正常に挿入またはアップサートされた各ドキュメントの
_id
を含む配列。
- ブール値は、 書込み保証(write concern)が有効化されて操作が実行された場合は
互換性
次の環境でホストされる配置には db.collection.bulkWrite()
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
注意
Atlas UI では一括書込み操作を実行できません。複数のドキュメントを挿入するには、ドキュメントの配列を挿入する必要があります。詳細については、Atlas ドキュメントの「ドキュメントの作成、表示、アップデート、および削除」を参照してください。
構文
bulkWrite()
メソッドの形式は次のとおりです。
db.collection.bulkWrite( [ <operation 1>, <operation 2>, ... ], { writeConcern : <document>, ordered : <boolean> } )
bulkWrite()
メソッドは次のパラメーターを取ります。
Parameter | タイプ | 説明 |
---|---|---|
operations | 配列 | |
writeConcern | ドキュメント | 任意。書込み保証(write concern)を表現するドキュメント。デフォルトの書込み保証を使用する場合は省略します。 トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。 |
ordered | ブール値 |
動作
bulkWrite()
書込み操作の配列を受け取り、それぞれを実行します。デフォルトでは、操作は順番に実行されます。書込み (write) 操作の実行順序を制御するには、「操作の実行」を参照してください。
書込み操作
insertOne
コレクションに単一のドキュメントを挿入します。
db.collection.bulkWrite( [ { insertOne : { "document" : <document> } } ] )
db.collection.insertOne()
を参照してください。
updateOne と updateMany
updateOne
は、コレクション内でフィルターに一致する単一のドキュメントをアップデートします。複数のドキュメントが一致する場合、updateOne
は最初に一致したドキュメントのみをアップデートします。
db.collection.bulkWrite( [ { updateOne : { "filter": <document>, "update": <document or pipeline>, "upsert": <boolean>, "collation": <document>, "arrayFilters": [ <filterdocument1>, ... ], "hint": <document|string> } } ] )
updateMany
は、コレクション内でフィルターに一致するすべてのドキュメントをアップデートします。
db.collection.bulkWrite( [ { updateMany : { "filter" : <document>, "update" : <document or pipeline>, "upsert" : <boolean>, "collation": <document>, "arrayFilters": [ <filterdocument1>, ... ], "hint": <document|string> } } ] )
フィールド | ノート |
---|---|
filter | 更新の選択基準。 db.collection.find() メソッドと同じクエリ セレクターを使用できます。 |
update | |
upsert | 任意。アップサートを実行するかどうかを示すブール値。 デフォルトでは、 |
arrayFilters | 任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。 |
collation | 任意。操作に使用する照合を指定します。 |
hint | 任意。アップデート filter をサポートするために使用するインデックス。 存在しないインデックスを指定した場合、操作はエラーになります。 |
詳細については、db.collection.updateOne()
と db.collection.updateMany()
を参照してください。
replaceOne
replaceOne
フィルタにマッチするコレクション内の単一のドキュメントを置き換えます。複数のドキュメントが一致する場合、replaceOne
は最初に一致したドキュメントのみを置換します。
db.collection.bulkWrite([ { replaceOne : { "filter" : <document>, "replacement" : <document>, "upsert" : <boolean>, "collation": <document>, "hint": <document|string> } } ] )
フィールド | ノート |
---|---|
filter | 置換操作の選択基準。 db.collection.find() メソッドと同じクエリ セレクターが使用できます。 |
replacement | 置換ドキュメントです。このドキュメントに更新演算子を含めることはできません。 |
upsert | 任意。アップサートを実行するかどうかを示すブール値。デフォルトでは、 upsert は false です。 |
collation | 任意。操作に使用する照合を指定します。 |
hint | 任意。アップデート filter をサポートするために使用するインデックス。 存在しないインデックスを指定した場合、操作はエラーになります。 |
詳細については db.collection.replaceOne()
を参照してください。
deleteOne と deleteMany
deleteOne
は、コレクション内でフィルターに一致する単一のドキュメントを削除します。複数のドキュメントが一致する場合、deleteOne
は最初に一致したドキュメントのみを削除します。
db.collection.bulkWrite([ { deleteOne : { "filter" : <document>, "collation" : <document> // Available starting in 3.4 } } ] )
deleteMany
は、コレクション内でフィルターに一致するすべてのドキュメントを削除します。
db.collection.bulkWrite([ { deleteMany: { "filter" : <document>, "collation" : <document> // Available starting in 3.4 } } ] )
フィールド | ノート |
---|---|
filter | 削除操作の選択基準。 db.collection.find() メソッドと同じクエリ セレクターが使用できます。 |
collation | 任意。操作に使用する照合を指定します。 |
詳細については、db.collection.deleteOne()
と db.collection.deleteMany()
を参照してください。
_id
フィールド
ドキュメントで _id フィールドが指定されていない場合は、 mongod
で _id
フィールドが追加され、ドキュメントの挿入またはアップサートの前にユニークな ObjectId()
が割り当てられます。ほとんどのドライバーでは ObjectId が作成され、 _id
フィールドが挿入されますが、ドライバーやアプリケーションでこの処理が行われない場合は、 mongod
で_id
の作成と入力が行われます。
ドキュメントに _id
フィールドが含まれる場合に重複キー エラーを回避するには、_id
値がコレクション内で一意になるようにする必要があります。
更新操作または置換操作では、元のドキュメントと異なる _id
値を指定することはできません。
操作の実行
ordered
パラメーターでは、bulkWrite()
が順番に操作を実行するか指定します。デフォルトでは、操作は順番に実行されます。
次のコードは、5 つの操作を含む bulkWrite()
を表します。
db.collection.bulkWrite( [ { insertOne : <document> }, { updateOne : <document> }, { updateMany : <document> }, { replaceOne : <document> }, { deleteOne : <document> }, { deleteMany : <document> } ] )
デフォルトである ordered : true
の状態では、最初の操作 insertOne
から最後の操作 deleteMany
まで、各操作が順番に実行されます。
ordered
が false に設定されている場合、パフォーマンスを向上させるために mongod
によって操作の順序が並べ替えられることがあります。アプリケーションは操作の実行順序に依存すべきではありません。
次のコードは、6 つの操作を含む順序付けられていない bulkWrite()
を表します。
db.collection.bulkWrite( [ { insertOne : <document> }, { updateOne : <document> }, { updateMany : <document> }, { replaceOne : <document> }, { deleteOne : <document> }, { deleteMany : <document> } ], { ordered : false } )
ordered : false
の場合、操作の結果が異なる場合があります。たとえば、 deleteOne
または deleteMany
では、 insertOne
、 updateOne
、 updateMany
、 replaceOne
の操作の前に実行されるか、後に実行されるかによって、削除されるドキュメントの数が増減する場合があります。
各グループ内の操作の数は、データベースのmaxWriteBatchSizeの値を超えることはできません。 MongoDB 3.6 以降、この値は100,000
です。 この値はhello.maxWriteBatchSize
フィールドに表示されます。
この制限により、エラー メッセージの肥大化の問題が回避されます。この制限を超えるグループがある場合、クライアント ドライバーによって、操作数が制限値以下となる小さなグループに分割されます。たとえば、maxWriteBatchSize
の値が 100,000
の場合、キューに 200,000
回の操作が含まれていると、ドライバによってそれぞれの操作回数が 100,000
回となるグループが 2 個作成されます。
注意
ドライバーによってグループが複数の小さなグループに分割されるのは、ハイレベル API を使用している場合のみに限られます。 db.runCommand()を直接使用する場合(例えばドライバーを書き込む場合)、制限を超えるバッチ書込みを実行しようとすると、MongoDB ではエラーがスローされます。
MongoDB 3.6 以降では、1 つのバッチのエラーレポートが大きくなりすぎると、MongoDB は残りのすべてのエラーメッセージを切り捨てて空の string にします。 現在のところ、 は、少なくとも 2 つのエラーメッセージがあり、合計サイズが1MB
を超えると、開始されます。
サイズとグループ化の仕組みは内部的パフォーマンスの細部に該当し、今後のバージョンで変更される可能性があります。
シャーディングされたコレクションで ordered
操作リストを実行すると、通常、 unordered
リストの実行よりも時間がかかります。これは、ordered リストでは毎回の操作で前の操作の完了を待機する必要があるためです。
上限付きコレクション
bulkWrite()
書き込み (write) 操作は、上限付きコレクションで使用する場合、制限があります。
updateOne
update
条件によって変更されているドキュメントのサイズが増加する場合には、 updateMany
により WriteError
がスローされます。
replaceOne
replacement
ドキュメントのサイズが元のドキュメントよりも大きい場合は WriteError
がスローされます。
deleteOne
deleteMany
では、上限付きコレクションで使用された場合に WriteError
がスローされます。
時系列コレクション
bulkWrite()
書込み (write) 操作は、時系列コレクションで使用する場合、制限があります。時系列コレクションで使用できるのは insertOne
のみです。他のすべての操作は WriteError
を返します。
Error Handling
db.collection.bulkWrite()
は、エラー時に BulkWriteError
例外をスローします。「トランザクション内のエラー処理」を参照してください。
書込み保証エラーを除き、順序付き操作はエラーの発生後に停止します。一方、順序なし操作は、トランザクション内で実行されない限り、キューにある残りの書込み操作の処理を続行します。 「トランザクション内でのエラー処理 」を参照してください。
書込み保証エラーは writeConcernErrors
フィールドに表示され、その他すべてのエラーは writeErrors
フィールドに表示されます。エラーが発生した場合、挿入された_id
値の代わりに、成功した書き込み操作の数が表示されます。実行順序の決まった操作では、発生したエラーが 1 つだけ表示され、実行順序のない操作では 1 つの配列内のそれぞれのエラーが表示されます。
スキーマ検証エラー
コレクションでスキーマ検証が使用されており、 validationAction
がerror
に設定されている場合、無効なドキュメントを挿入したり、無効な値を持つドキュメントを更新したりすると、エラーがスローされます。 operations
配列内の無効な操作に先行する操作が実行され、 コレクションに書き込まれます。 ordered
フィールドは、残りの操作が実行されるかどうかを決定します。
トランザクション
db.collection.bulkWrite()
は分散トランザクション内で使用できます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
トランザクション内での挿入とアップサート
機能の互換性バージョン (FCV) が"4.4"
以上の場合、存在しないコレクションに対してトランザクションで upsert: true
を使用した挿入操作またはアップデート操作を実行すると、コレクションが暗黙的に作成されます。
注意
クロスシャードの書き込みトランザクションでは新しいコレクションを作成できません。たとえば、あるシャードで既存コレクションに書き込み、別のシャードで暗示的にコレクションを作成する場合、MongoDB では同じトランザクションで両方の操作を実行できません。
書込み保証とトランザクション
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
トランザクション内のエラー処理
MongoDB4 .2 以降では、トランザクション内で db.collection.bulkWrite()
操作にエラーが発生した場合、メソッドは BulkWriteException をスローします (トランザクション外と同様)。
4.0 では、 bulkWrite
操作でトランザクション内のエラーが発生した場合、スローされたエラーは BulkWriteException
としてはラップされません。
トランザクション内では、一括書き込みで最初のエラーが発生すると、順序付けがない場合であっても一括書き込み全体が失敗し、トランザクションが中止されます。
例
順序付き一括書込みの例
bulkWrite()
操作の順序とエラー処理を理解することが重要です。bulkWrite()
はデフォルトで順序が付いたリストの操作を実行します。
操作は連続して実行されます。
操作にエラーがある場合、その操作および後続の操作は実行されません。
エラー操作が完了する前に一覧表示された操作。
bulkWrite()
の例では、pizzas
コレクションを使用します。
db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] )
次の bulkWrite()
の例では、pizzas
コレクションに対して以下の操作を実行します。
insertOne
を使用して 2 つのドキュメントを追加します。updateOne
を使用してドキュメントをアップデートします。deleteOne
を使用してドキュメントを削除します。replaceOne
を使用してドキュメントを置換します。
try { db.pizzas.bulkWrite( [ { insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } }, { insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } }, { updateOne: { filter: { type: "cheese" }, update: { $set: { price: 8 } } } }, { deleteOne: { filter: { type: "pepperoni"} } }, { replaceOne: { filter: { type: "vegan" }, replacement: { type: "tofu", size: "small", price: 4 } } } ] ) } catch( error ) { print( error ) }
完了した操作の概要を含む出力例を示します。
{ acknowledged: true, insertedCount: 2, insertedIds: { '0': 3, '1': 4 }, matchedCount: 2, modifiedCount: 2, deletedCount: 1, upsertedCount: 0, upsertedIds: {} }
前の bulkWrite()
の例を実行する前に、コレクションに _id
が 4
のドキュメントがすでに含まれていた場合、2 番目の insertOne
操作に対して以下の重複キー例外が返されます。
writeErrors: [ WriteError { err: { index: 1, code: 11000, errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 4 }', op: { _id: 4, type: 'sausage', size: 'large', price: 10 } } } ], result: BulkWriteResult { result: { ok: 1, writeErrors: [ WriteError { err: { index: 1, code: 11000, errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 4 }', op: { _id: 4, type: 'sausage', size: 'large', price: 10 } } } ], writeConcernErrors: [], insertedIds: [ { index: 0, _id: 3 }, { index: 1, _id: 4 } ], nInserted: 1, nUpserted: 0, nMatched: 0, nModified: 0, nRemoved: 0, upserted: [] } }
bulkWrite()
の例は順序付けられているため、最初の insertOne
操作のみが完了します。
エラーのないすべての操作を完了するには、ordered
を false
に設定して bulkWrite()
を実行します。例については、次のセクションを参照してください。
順序付けなし一括書込みの例
順序付けられていないbulkWrite()
を指定するには、 ordered
を false
に設定します。
順序付けられていない bulkWrite()
の操作リストでは次のようになります。
操作は並行して実行可能です(保証はされません)。詳細については順序付き操作と順序なし操作を参照してください。
エラーのある操作は完了しません。
エラーのないすべての操作が完了します。
pizzas
コレクションの例を引き続き使用し、コレクションの削除と再作成を行います。
db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] )
次の例を参照してください。
bulkWrite()
はpizzas
コレクションに対して順序のない操作を実行します。2番目の
insertOne
操作の_id
は 1 番目のinsertOne
と同じであるため、重複キー エラーが発生します。
try { db.pizzas.bulkWrite( [ { insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } }, { insertOne: { document: { _id: 3, type: "sausage", size: "large", price: 10 } } }, { updateOne: { filter: { type: "cheese" }, update: { $set: { price: 8 } } } }, { deleteOne: { filter: { type: "pepperoni"} } }, { replaceOne: { filter: { type: "vegan" }, replacement: { type: "tofu", size: "small", price: 4 } } } ], { ordered: false } ) } catch( error ) { print( error ) }
出力例には、重複キー エラーと完了した操作の概要が含まれています。
writeErrors: [ WriteError { err: { index: 1, code: 11000, errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 3 }', op: { _id: 3, type: 'sausage', size: 'large', price: 10 } } } ], result: BulkWriteResult { result: { ok: 1, writeErrors: [ WriteError { err: { index: 1, code: 11000, errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 3 }', op: { _id: 3, type: 'sausage', size: 'large', price: 10 } } } ], writeConcernErrors: [], insertedIds: [ { index: 0, _id: 3 }, { index: 1, _id: 3 } ], nInserted: 1, nUpserted: 0, nMatched: 2, nModified: 2, nRemoved: 1, upserted: [] } }
重複キー エラーのため、2 番目のinsertOne
操作は正常に実行されません。順序付けられていない bulkWrite()
では、エラーのないすべての操作が完了します。
書込み保証を使用した一括書込みの例
pizzas
コレクションの例を引き続き使用し、コレクションの削除と再作成を行います。
db.pizzas.insertMany( [ { _id: 0, type: "pepperoni", size: "small", price: 4 }, { _id: 1, type: "cheese", size: "medium", price: 7 }, { _id: 2, type: "vegan", size: "large", price: 8 } ] )
次の bulkWrite()
の例では、 pizzas
コレクションに対して操作を実行し、100 ミリ秒のタイムアウトで"majority"
書込み保証 (write concern) を設定します。
try { db.pizzas.bulkWrite( [ { updateMany: { filter: { size: "medium" }, update: { $inc: { price: 0.1 } } } }, { updateMany: { filter: { size: "small" }, update: { $inc: { price: -0.25 } } } }, { deleteMany: { filter: { size: "large" } } }, { insertOne: { document: { _id: 4, type: "sausage", size: "small", price: 12 } } } ], { writeConcern: { w: "majority", wtimeout: 100 } } ) } catch( error ) { print( error ) }
レプリカ セット ノードの大半が操作を確認するまでの時間が wtimeout
を超えると、この例では書込み保証エラーと完了した操作の概要が返されます。
result: BulkWriteResult { result: { ok: 1, writeErrors: [], writeConcernErrors: [ WriteConcernError { err: { code: 64, codeName: 'WriteConcernFailed', errmsg: 'waiting for replication timed out', errInfo: { wtimeout: true, writeConcern: [Object] } } } ], insertedIds: [ { index: 3, _id: 4 } ], nInserted: 0, nUpserted: 0, nMatched: 2, nModified: 2, nRemoved: 0, upserted: [], opTime: { ts: Timestamp({ t: 1660329086, i: 2 }), t: Long("1") } } }