db.collection.updateMany()
MongoDB とドライバー
このページでは、 mongosh
メソッドについて説明します。MongoDB ドライバーで同等のメソッドを確認するには、ご使用のプログラミング言語の対応するページを参照してください。
定義
互換性
次の環境でホストされる配置には db.collection.updateMany()
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
updateMany()
メソッドの形式は次のとおりです。
db.collection.updateMany( <filter>, <update>, { upsert: <boolean>, writeConcern: <document>, collation: <document>, arrayFilters: [ <filterdocument1>, ... ], hint: <document|string>, let: <document> } )
パラメーター
updateMany()
メソッドは次のパラメーターを取ります。
Parameter | タイプ | 説明 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ドキュメント | ||||||||||||||||||||
ドキュメントまたはパイプライン | 適用される変更内容。次のいずれかになります。
置き換えドキュメントを使用して更新するには、 | |||||||||||||||||||
upsert | ブール値 | 任意。
複数のアップサートを回避するため、 デフォルトは | ||||||||||||||||||
writeConcern | ドキュメント | 任意。書込み保証(write concern)を表現するドキュメント。デフォルトの書込み保証を使用する場合は省略します。 トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。 | ||||||||||||||||||
collation | ドキュメント | 任意。 操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。
照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 バージョン 3.4 で追加。 | ||||||||||||||||||
arrayFilters | 配列 | 任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。 アップデート ドキュメントでは、
アップデート ドキュメントには同じ識別子を複数回含めることができます。ただし、アップデート ドキュメント内の個別の識別子 (
ただし、次の例のように、単一のフィルター ドキュメント内の同じ識別子に複合条件を指定できます。
例については、「配列更新オペレーションでの バージョン 3.6 の新機能。 | ||||||||||||||||||
ドキュメントまたは文字列 | 任意。 クエリ述語 をサポートするために使用する インデックス を指定するドキュメントまたは string です。 このオプションには、インデックス仕様ドキュメントまたはインデックス名の文字列を指定できます。 存在しないインデックスを指定した場合、操作はエラーになります。 例については、「更新操作での | |||||||||||||||||||
let | ドキュメント | 任意。 変数のリストを含むドキュメントを指定します。これにより、変数をクエリテキストから分離することで、コマンドの読みやすさを向上させることができます。 ドキュメントの構文は次のとおりです。
変数は式によって返された値に設定され、その後は変更できません。 コマンド内の変数の値にアクセスするには、二重ドル記号の接頭辞( 結果のフィルタリングに変数を使用するには、
|
戻り値
このメソッドは、次の内容を含むドキュメントを返します。
操作が書き込み保証付きで実行された場合はブール値
acknowledged
(true
)、書き込み保証が無効になっている場合はfalse
になりますmatchedCount
一致したドキュメントの数を含みますmodifiedCount
変更されたドキュメントの数を含みますupsertedId
、アップサートされたドキュメントの_id
が含まれるupsertedCount
アップサートされた文書の数を含む
アクセス制御
authorization
を使用して実行されている配置では、ユーザーには次の特権を含むアクセス権が必要です。
update
指定したコレクションに対するアクション。find
指定したコレクションに対するアクション。insert
操作の結果がアップサートになる場合、指定されたコレクションに対して実行されるアクション。
組み込みロール readWrite
は必要な特権を提供します。
動作
updateMany()
は、 update
基準を使用して変更を適用し、コレクション内のfilter
に一致するすべてのドキュメントを更新します。
アップサート
upsert: true
で、filter
に一致するドキュメントがない場合、db.collection.updateMany()
では filter
と update
パラメーターに基づき新しいドキュメントが作成されます。
シャーディングされたコレクションで upsert: true
を指定する場合、filter
には完全なシャードキーを含める必要があります。追加の db.collection.updateMany()
動作については、「シャーディングされたコレクション」を参照してください。
「アップサートによる複数のドキュメントの更新」を参照してください。
更新演算子式ドキュメントを使用したアップデート
変更仕様の場合、db.collection.updateMany()
メソッドでは更新演算子式のみを含むドキュメントを受け入れ可能です。
以下に例を挙げます。
db.collection.updateMany( <query>, { $set: { status: "D" }, $inc: { quantity: 2 } }, ... )
集計パイプラインによる更新
db.collection.updateMany()
メソッドでは、集計パイプライン [ <stage1>, <stage2>, ... ]
を受け入れて、実行する変更を指定できます。このパイプラインには次のステージが含まれる可能性があります。
$addFields
およびそのエイリアス$set
$replaceRoot
とそのエイリアス$replaceWith
。
集計パイプラインを使用すると、現在のフィールド値に基づいて条件付きのアップデートを表現したり、あるフィールドを他のフィールドの値を使用してアップデートするなど、より表現内容の多いアップデート ステートメントが可能になります。
以下に例を挙げます。
db.collection.updateMany( <query>, [ { $set: { status: "Modified", comments: [ "$misc1", "$misc2" ] } }, { $unset: [ "misc1", "misc2" ] } ] ... )
注意
このパイプラインでは、$set
と $unset
は集計ステージで、更新演算子とは対照的です。集計ステージ$set
と$unset
では、ドキュメントに新しいフィールドが追加され、既存のフィールド値は変更されません。
更新演算子の詳細については、 $set
と$unset
を参照してください。
例については、「集計パイプラインによる更新」を参照してください。
上限付きコレクション
更新操作によりドキュメントのサイズが変更された場合、操作は失敗します。
時系列コレクション
updateMany()
メソッドは、MongoDB 5.1 以降の時系列コレクションで使用できます。
シャーディングされたコレクション
db.collection.updateMany()
操作のうち upsert: true
を含み、かつシャーディングされたコレクションにあるものには、filter
に完全なシャードキーを含める必要があります。
説明可能性
トランザクション
db.collection.updateMany()
は分散トランザクション内で使用できます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
トランザクション内のアップサート
トランザクションがクロスシャード間書込みトランザクション(write transaction)でない場合に、分散トランザクション内にコレクションとインデックスを作成できます。
db.collection.updateMany()
と upsert: true
は、既存のコレクションまたは存在しないコレクションで実行できます。存在しないコレクションに対して実行すると、操作によってコレクションが作成されます。
書込み保証とトランザクション
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
Oplog エントリ
db.collection.updateMany()
操作によって 1 つ以上のドキュメントが正常に更新されると、その操作によって更新された各ドキュメント用のエントリがoplog (操作ログ)に追加されます。 操作が失敗した場合、または更新するドキュメントが見つからなかった場合は、その操作によって oplog にエントリーが追加されることはありません。
例
複数のドキュメントの更新
restaurant
コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "name" : "Central Perk Cafe", "violations" : 3 } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "violations" : 2 } { "_id" : 3, "name" : "Empire State Sub", "violations" : 5 } { "_id" : 4, "name" : "Pizza Rat's Pizzaria", "violations" : 8 }
次の操作は、 violations
が 4
より大きいすべてのドキュメントを更新し、$set
フラグを "レビュー" に設定します。
try { db.restaurant.updateMany( { violations: { $gt: 4 } }, { $set: { "Review" : true } } ); } catch (e) { print(e); }
この操作では以下が返されます。
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
コレクションには、次のドキュメントが含まれています。
{ "_id" : 1, "name" : "Central Perk Cafe", "violations" : 3 } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "violations" : 2 } { "_id" : 3, "name" : "Empire State Sub", "violations" : 5, "Review" : true } { "_id" : 4, "name" : "Pizza Rat's Pizzaria", "violations" : 8, "Review" : true }
一致するものが見つからなかった場合、以下の結果が返されます。
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }
upsert: true
を設定すると、一致するものが見つからない場合にはドキュメントが挿入されます。
集約パイプラインによるアップデート
db.collection.updateMany()
は、更新に集計パイプラインを使用できます。パイプラインは、次のステージで設定できます。
$addFields
およびそのエイリアス$set
$replaceRoot
とそのエイリアス$replaceWith
。
集計パイプラインを使用すると、現在のフィールド値に基づいて条件付きのアップデートを表現したり、あるフィールドを他のフィールドの値を使用してアップデートするなど、より表現内容の多いアップデート ステートメントが可能になります。
例 1: 既存のフィールドを使用した集計パイプラインによる更新
次の例では、集計パイプラインを使用して、ドキュメント内の他のフィールドの値を使用してフィールドを変更します。
次のドキュメントを使用して students
コレクションを作成します。
db.students.insertMany( [ { "_id" : 1, "student" : "Skye", "points" : 75, "commentsSemester1" : "great at math", "commentsSemester2" : "loses temper", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }, { "_id" : 2, "students" : "Elizabeth", "points" : 60, "commentsSemester1" : "well behaved", "commentsSemester2" : "needs improvement", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") } ] )
commentsSemester1
フィールドと commentsSemester2
フィールドを別々にするのではなく、これらを新しい comments
フィールドにまとめるとします。次に示す更新操作では、集計パイプラインを使用して次のようにします。
新しい
comments
フィールドを追加し、lastUpdate
フィールドを設定します。コレクション内にあるすべてのドキュメントの
commentsSemester1
フィールドとcommentsSemester2
フィールドを削除します。
db.students.updateMany( { }, [ { $set: { comments: [ "$commentsSemester1", "$commentsSemester2" ], lastUpdate: "$$NOW" } }, { $unset: [ "commentsSemester1", "commentsSemester2" ] } ] )
注意
このパイプラインでは、$set
と $unset
は集計ステージで、更新演算子とは対照的です。集計ステージ$set
と$unset
では、ドキュメントに新しいフィールドが追加され、既存のフィールド値は変更されません。
更新演算子の詳細については、 $set
と$unset
を参照してください。
コマンドの実行後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "student" : "Skye", "status" : "Modified", "points" : 75, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "great at math", "loses temper" ] } { "_id" : 2, "student" : "Elizabeth", "status" : "Modified", "points" : 60, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "well behaved", "needs improvement" ] }
例 2: 既存のフィールドの条件を使用した集計パイプラインによる更新
集計パイプラインを使用すると、現在のフィールド値に基づく条件付きアップデートを実行したり、アップデート時に別個のフィールド値の計算に現在のフィールド値を使用することができます。
たとえば、以下のドキュメントでstudents3
コレクションを作成する場合、
db.students3.insertMany( [ { "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }, { "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }, { "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") } ] )
集計パイプラインを使用すると、計算されたグレード平均およびレターグレードでドキュメントを更新することができます。
db.students3.updateMany( { }, [ { $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] } , lastUpdate: "$$NOW" } }, { $set: { grade: { $switch: { branches: [ { case: { $gte: [ "$average", 90 ] }, then: "A" }, { case: { $gte: [ "$average", 80 ] }, then: "B" }, { case: { $gte: [ "$average", 70 ] }, then: "C" }, { case: { $gte: [ "$average", 60 ] }, then: "D" } ], default: "F" } } } } ] )
注意
このパイプラインでは、$set
と $unset
は集計ステージで、更新演算子とは対照的です。集計ステージ$set
と$unset
では、ドキュメントに新しいフィールドが追加され、既存のフィールド値は変更されません。
更新演算子の詳細については、 $set
と$unset
を参照してください。
- 第 1 ステージ
$set
段階:- 第 2 ステージ
$set
ステージでは、前のステージで計算されたaverage
フィールドに基づいて新しいフィールドgrade
が計算されます。集計演算子$switch
の詳細については、$switch
を参照してください。
コマンドの実行後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2020-01-24T17:31:01.670Z"), "average" : 92, "grade" : "A" } { "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2020-01-24T17:31:01.670Z"), "average" : 90, "grade" : "A" } { "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2020-01-24T17:31:01.670Z"), "average" : 75, "grade" : "C" }
アップサートによる複数のドキュメントの更新
inspectors
コレクションには次のドキュメントが含まれます。
{ "_id" : 92412, "inspector" : "F. Drebin", "Sector" : 1, "Patrolling" : true }, { "_id" : 92413, "inspector" : "J. Clouseau", "Sector" : 2, "Patrolling" : false }, { "_id" : 92414, "inspector" : "J. Clouseau", "Sector" : 3, "Patrolling" : true }, { "_id" : 92415, "inspector" : "R. Coltrane", "Sector" : 3, "Patrolling" : false }
次の操作では、 Sector
が 4 より大きく、 inspector
が "R. Coltrane"
に等しいすべてのドキュメントを更新します。
try { db.inspectors.updateMany( { "Sector" : { $gt : 4 }, "inspector" : "R. Coltrane" }, { $set: { "Patrolling" : false } }, { upsert: true } ); } catch (e) { print(e); }
この操作では以下が返されます。
{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0, "upsertedId" : ObjectId("56fc5dcb39ee682bdc609b02"), "upsertedCount": 1 }
コレクションには、次のドキュメントが含まれています。
{ "_id" : 92412, "inspector" : "F. Drebin", "Sector" : 1, "Patrolling" : true }, { "_id" : 92413, "inspector" : "J. Clouseau", "Sector" : 2, "Patrolling" : false }, { "_id" : 92414, "inspector" : "J. Clouseau", "Sector" : 3, "Patrolling" : true }, { "_id" : 92415, "inspector" : "R. Coltrane", "Sector" : 3, "Patrolling" : false }, { "_id" : ObjectId("56fc5dcb39ee682bdc609b02"), "inspector" : "R. Coltrane", "Patrolling" : false }
フィルターに一致するドキュメントがなく、upsert
が true
であったため、updateMany()
では生成された _id
、filter
と同じ条件、および update
修飾子を持つドキュメントが挿入されました。
書き込み保証による更新
3つのノードから成るレプリカセットにおいて、次の操作は w
の majority
と wtimeout
の 100
を指定します。
try { db.restaurant.updateMany( { "name" : "Pizza Rat's Pizzaria" }, { $inc: { "violations" : 3}, $set: { "Closed" : true } }, { w: "majority", wtimeout: 100 } ); } catch (e) { print(e); }
確認応答にwtimeout
の制限を超える時間がかかると、次の例外が発生します。
WriteConcernError({ "code" : 64, "errmsg" : "waiting for replication timed out", "errInfo" : { "wtimeout" : true, "writeConcern" : { "w" : "majority", "wtimeout" : 100, "provenance" : "getLastErrorDefaults" } } })
次の表は、errInfo.writeConcern.provenance
の値について説明したものです。
出所 | 説明 |
---|---|
clientSupplied | 書き込み保証(write concern)がアプリケーションで指定されました。 |
customDefault | 書込み保証 (write concern) は、カスタム定義されたデフォルト値に基づきます。 setDefaultRWConcern を参照してください。 |
getLastErrorDefaults | 書込み保証 (write concern) は、レプリカセットの settings.getLastErrorDefaults のフィールドに基づきます。 |
implicitDefault | 他の書き込み保証(write concern)が一切指定されていない状態で、サーバーから発生した書き込み保証。 |
照合の指定
バージョン 3.4 で追加。
照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。
コレクション myColl
は、次のドキュメントを含みます。
{ _id: 1, category: "café", status: "A" } { _id: 2, category: "cafe", status: "a" } { _id: 3, category: "cafE", status: "a" }
次の操作には照合オプションが含まれます。
db.myColl.updateMany( { category: "cafe" }, { $set: { status: "Updated" } }, { collation: { locale: "fr", strength: 1 } } );
配列更新操作での arrayFilters
の指定
配列フィールドを更新するときに、どの配列要素を更新するかを決定するためのarrayFilters
を指定できます。
arrayFilters
条件に一致する要素を更新する
次のドキュメントを使用してコレクション students
を作成します。
db.students.insertMany( [ { "_id" : 1, "grades" : [ 95, 92, 90 ] }, { "_id" : 2, "grades" : [ 98, 100, 102 ] }, { "_id" : 3, "grades" : [ 95, 110, 100 ] } ] )
grades
配列にある 100
以上の要素をすべて更新するには、フィルタリングした位置演算子 $[<identifier>]
を arrayFilters
オプションとともに使用します。
db.students.updateMany( { grades: { $gte: 100 } }, { $set: { "grades.$[element]" : 100 } }, { arrayFilters: [ { "element": { $gte: 100 } } ] } )
操作後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 100 ] } { "_id" : 3, "grades" : [ 95, 100, 100 ] }
ドキュメントの配列の特定の要素を更新する
次のドキュメントを使用してコレクション students2
を作成します。
db.students2.insertMany( [ { "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] }, { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] } ] )
grades
配列のすべての要素のうち、グレードが 85
以上のもので mean
フィールドの値を変更するには、フィルタリングされた位置演算子 $[<identifier>]
を arrayFilters
とともに使用します。
db.students2.updateMany( { }, { $set: { "grades.$[elem].mean" : 100 } }, { arrayFilters: [ { "elem.grade": { $gte: 85 } } ] } )
操作後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 100, "std" : 4 }, { "grade" : 85, "mean" : 100, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 100, "std" : 6 }, { "grade" : 87, "mean" : 100, "std" : 3 }, { "grade" : 85, "mean" : 100, "std" : 4 } ] }
更新操作に hint
を指定する
次のドキュメントを使用してサンプルstudents
コレクションを作成します。
db.students.insertMany( [ { "_id" : 1, "student" : "Richard", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null }, { "_id" : 2, "student" : "Jane", "grade" : "A", "points" : 60, "comments1" : "well behaved", "comments2" : "fantastic student" }, { "_id" : 3, "student" : "Ronan", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null }, { "_id" : 4, "student" : "Noah", "grade" : "D", "points" : 20, "comments1" : "needs improvement", "comments2" : null }, { "_id" : 5, "student" : "Adam", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null }, { "_id" : 6, "student" : "Henry", "grade" : "A", "points" : 86, "comments1" : "fantastic student", "comments2" : "well behaved" } ] )
コレクションに次のインデックスを作成します。
db.students.createIndex( { grade: 1 } )
次の更新操作は、インデックス{
grade: 1 }
を使用することを明示的に示しています。
注意
存在しないインデックスを指定した場合、操作はエラーになります。
db.students.updateMany( { "points": { $lte: 20 }, "grade": "F" }, { $set: { "comments1": "failed class" } }, { hint: { grade: 1 } } )
update コマンドは次を返します。
{ "acknowledged" : true, "matchedCount" : 3, "modifiedCount" : 3 }
ヒントで指定したインデックスが使用されているかどうかを確認するには、$indexStats
パイプラインを実行します。
db.students.aggregate( [ { $indexStats: { } }, { $sort: { name: 1 } }, { $match: {key: { grade: 1 } } } ] )