db.collection.update()
定義
db.collection.update(query, update, options)
既存のドキュメント、またはコレクション内のドキュメントを変更します。このメソッドは、update パラメータに応じて、既存のドキュメントの特定のフィールドを変更したり、既存のドキュメント全体を置き換えたりすることができます。
デフォルトでは、
db.collection.update()
メソッドは 単一のドキュメントを更新します。クエリ条件に一致するすべてのドキュメントを更新するには、オプション multi: true を含めます。
互換性
次の環境でホストされる配置には db.collection.update()
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
Atlas UI を使用して MongoDB Atlas でホストされているドキュメントを更新する方法については、 「 1 つのドキュメントの編集 」を参照してください。
構文
バージョン 5.0 での変更。
db.collection.update()
メソッドの形式は次のとおりです。
db.collection.update( <query>, <update>, { upsert: <boolean>, multi: <boolean>, writeConcern: <document>, collation: <document>, arrayFilters: [ <filterdocument1>, ... ], hint: <document|string>, let: <document> // Added in MongoDB 5.0 } )
パラメーター
db.collection.update()
メソッドは次のパラメーターを取ります。
Parameter | タイプ | 説明 | ||||||
---|---|---|---|---|---|---|---|---|
ドキュメント | ||||||||
ドキュメントまたはパイプライン | 適用される変更内容。次のいずれかになります。
詳細と例については、「Oplog エントリ」を参照してください。 | |||||||
ブール値 | 任意。
複数のアップサートを回避するには、 デフォルトは | |||||||
ブール値 | 任意。 | |||||||
ドキュメント | 任意。書込み保証 (write concern) を表現するドキュメント。省略すると、デフォルトの書込み保証 (write concern) トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
| |||||||
ドキュメント | ||||||||
配列 | 任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。 アップデート ドキュメントでは、 注意識別子が更新ドキュメントに含まれていない場合、識別子の配列フィルター ドキュメントを作成することはできません。 例については、「配列アップデート操作に | |||||||
ドキュメントまたは文字列 | 任意。 クエリ述語 をサポートするために使用する インデックス を指定するドキュメントまたは string です。 このオプションには、インデックス仕様ドキュメントまたはインデックス名の文字列を指定できます。 存在しないインデックスを指定した場合、操作はエラーになります。 例については、「更新操作での | |||||||
ドキュメント | 任意。 変数のリストを含むドキュメントを指定します。これにより、変数をクエリテキストから分離することで、コマンドの読みやすさを向上させることができます。 ドキュメントの構文は次のとおりです。
変数は式によって返された値に設定され、その後は変更できません。 コマンド内の変数の値にアクセスするには、二重ドル記号の接頭辞( 結果のフィルタリングに変数を使用するには、
バージョン 5.0 で追加 |
戻り値
このメソッドは、操作のステータスを含む WriteResult ドキュメントを返します。
アクセス制御
authorization
を使用して実行されている配置では、ユーザーには次の特権を含むアクセス権が必要です。
update
指定したコレクションに対するアクション。find
指定したコレクションに対するアクション。insert
操作の結果がアップサートになる場合、指定されたコレクションに対して実行されるアクション。
組み込みロール readWrite
は必要な特権を提供します。
動作
$expr
を使用した更新で を使用するUpsert
$expr 演算子を使用して upsert フラグを true
に設定しようとすると、エラーが発生します。
シャーディングされたコレクション
シャーディングされたコレクションで db.collection.update()
を multi: false
と一緒に使用するには、_id
フィールドに完全一致を含めるか、単一のシャードをターゲットにする(シャードキーを含めるなど)必要があります。
db.collection.update()
が更新操作(ドキュメント置換操作ではない)を実行する場合、db.collection.update()
では複数のシャードをターゲットにすることができます。
シャーディングされたコレクションでドキュメント操作を置換する
ドキュメント置き換え操作では、まずクエリフィルターを使用して 1 つのシャードに対象を絞り込もうとします。クエリフィルターで 1 つのシャードに絞り込めない場合は、置き換えドキュメントで絞り込もうとします。
以前のバージョンでは、この操作では置換ドキュメントを使用するターゲットを試行します。
upsert
シャーディングされたコレクション
upsert: true を含み、かつシャーディングされたコレクションにある db.collection.update()
の操作には、filter
に完全なシャードキーを含める必要があります。
更新操作に使用します。
ドキュメントの置き換え操作用。
ただし、シャーディングされたコレクション内のドキュメントにはシャードキーのフィールドがない場合があります。シャードキーがないドキュメントを対象とするには、null
を等価一致の を(_id
フィールド上と同じに)別のフィルター条件と組み合わせて使用できます。以下に例を挙げます。
{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key
シャードキーの変更
シャードキー フィールドが不変の _id
フィールドでない限り、ドキュメントのシャードキー値を更新できます。
既存のシャードキー値をdb.collection.update()
で変更するには
必ず
mongos
上で使用します。シャードに直接操作を実行しないでください。トランザクション内で、または 再試行可能な書き込みとして実行する必要があります。
必ず
multi: false
を指定します。完全なシャードキーに等価のクエリフィルターを含める必要があります。
Tip
欠落しているキー値は NULL 等価一致の一部として返されるため、NULL 値のキーが更新されないように、必要に応じて追加のクエリ条件(_id
フィールドなど)を追加します。
「シャーディングされたコレクションの upsert
」も参照してください。
欠落しているシャードキー
シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。db.collection.update()
を使用してドキュメントの欠落しているシャードキーを設定するには、mongos
で実行する必要があります。シャードに対して直接操作を実行しないでください。
さらに、次の要件も適用されます。
タスク | 要件 |
---|---|
設定するには null |
|
null 以外の値に設定するには |
|
Tip
欠落しているキー値は NULL 等価一致の一部として返されるため、NULL 値のキーが更新されないように、必要に応じて追加のクエリ条件(_id
フィールドなど)を追加します。
以下も参照してください。
トランザクション
db.collection.update()
は分散トランザクション内で使用できます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
トランザクション内のアップサート
トランザクションがクロスシャード間書き込みトランザクション(write transaction)でない場合に、分散トランザクション内にコレクションとインデックスを作成できます。
db.collection.update()
と upsert: true
は、既存のコレクションまたは存在しないコレクションで実行できます。存在しないコレクションに対して実行すると、操作によってコレクションが作成されます。
書込み保証とトランザクション
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
Oplog エントリ
db.collection.update()
操作によって 1 つ以上のドキュメントが正常に更新されると、その操作によって oplog(操作ログ)にエントリーが追加されます。操作が失敗した場合、または更新するドキュメントが見つからなかった場合は、その操作によって oplog にエントリーが追加されることはありません。
例
以下のタブでは、一般的な update()
操作のさまざまな例を紹介しています。
mongosh
では、次のドキュメントを含む books
コレクションが作成されます。このコマンドは、まず、以前に存在していたすべてのドキュメントを books
コレクションから排除します。
db.books.remove({}); db.books.insertMany([ { "_id" : 1, "item" : "TBD", "stock" : 0, "info" : { "publisher" : "1111", "pages" : 430 }, "tags" : [ "technology", "computer" ], "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ], "reorder" : false }, { "_id" : 2, "item" : "XYZ123", "stock" : 15, "info" : { "publisher" : "5555", "pages" : 150 }, "tags" : [ ], "ratings" : [ { "by" : "xyz", "rating" : 5 } ], "reorder" : false } ]);
更新演算子式の使用($inc
と$set
)
<update>
ドキュメントに、$set
修飾子を使用するような、更新演算子 が含まれている場合は、次のようになります。
<update>
ドキュメントには、更新演算子式のみを含める必要があります。db.collection.update()
メソッドは、ドキュメント内の対応するフィールドのみを更新します。埋め込みドキュメントまたは配列全体を更新するには、フィールドの置換値を指定します。
埋め込みドキュメントまたは配列内の特定のフィールドを更新するには、ドット表記を使用してフィールドを指定します。
db.books.update( { _id: 1 }, { $inc: { stock: 5 }, $set: { item: "ABC123", "info.publisher": "2222", tags: [ "software" ], "ratings.1": { by: "xyz", rating: 3 } } } )
この操作において:
<query>
の{ _id: 1 }
パラメーターは、更新するドキュメントを指定します。$inc
演算子は、stock
フィールドを増分し、$set
演算子は、次の値を置き換えます:item
フィールド、publisher
info
埋め込みドキュメント内のフィールド、tags
フィールド、ratings
配列の 2 番目の要素。
更新されたドキュメントは次のとおりです:
{ "_id" : 1, "item" : "ABC123", "stock" : 5, "info" : { "publisher" : "2222", "pages" : 430 }, "tags" : [ "software" ], "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ], "reorder" : false }
この操作は、次の SQL ステートメントに対応しています。
UPDATE books SET stock = stock + 5 item = "ABC123" publisher = 2222 pages = 430 tags = "software" rating_authors = "ijk,xyz" rating_values = "4,3" WHERE _id = 1
注意
query
パラメーターが複数のドキュメントと一致した場合、この操作では一致するドキュメントが 1 つだけ更新されます。複数のドキュメントを更新するには、multi
オプションを true
に設定する必要があります。
既存の配列に要素をプッシュする($push
)
次の操作では、$push
更新演算子を使用して、新しいオブジェクトを ratings
配列に追加します。
db.books.update( { _id: 2 }, { $push: { ratings: { "by" : "jkl", "rating" : 2 } } } )
更新されたドキュメントは次のとおりです:
{ "_id" : 2, "item" : "XYZ123", "stock" : 15, "info" : { "publisher" : "5555", "pages" : 150 }, "tags" : [ ], "ratings" : [ { "by" : "xyz", "rating" : 5 }, { "by" : "jkl", "rating" : 2 } ], "reorder" : false }
フィールドの削除($unset
)
次の操作では、 $unset
演算子を使用して、 { _id: 1 }
を持つドキュメントからtags
フィールドを削除します。
db.books.update( { _id: 1 }, { $unset: { tags: 1 } } )
更新されたドキュメントは次のとおりです:
{ "_id" : 1, "item" : "TBD", "stock" : 0, "info" : { "publisher" : "1111", "pages" : 430 }, "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ], "reorder" : false }
$unset
に相当する直接 SQL はありませんが、 $unset
は次の SQL コマンドに類似しており、 books
テーブルからtags
フィールドを削除します。
ALTER TABLE books DROP COLUMN tags
複数のドキュメントを更新する($update
とmulti
)
multi
がtrue
に設定されている場合、db.collection.update()
メソッドは <query>
条件を満たすすべてのドキュメントを更新します。multi
更新操作は他の読み取り/書き込み操作とインターリーブする可能性があります。
次の操作は、stock
が 10
以下であるすべてのドキュメントの reorder
フィールドを true
に設定します。reorder
フィールドが一致するドキュメントに存在しない場合、$set
演算子は指定された値を持つフィールドを追加します。
db.books.update( { stock: { $lte: 10 } }, { $set: { reorder: true } }, { multi: true } )
コレクション内の結果ドキュメントは次のとおりです。
[ { "_id" : 1, "item" : "ABC123", "stock" : 5, "info" : { "publisher" : "2222", "pages" : 430 }, "ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ], "reorder" : true } { "_id" : 2, "item" : "XYZ123", "stock" : 10, "info" : { "publisher" : "2255", "pages" : 150 }, "tags" : [ "baking", "cooking" ], "reorder" : true } ]
この操作は、次の SQL ステートメントに対応しています。
UPDATE books SET reorder=true WHERE stock <= 10
注意
置換を実行する場合、つまり <update> ドキュメントに field:value
の式のみが含まれている場合は、multi: true
を指定できません。
一致するものが存在しない場合は新しいドキュメントを挿入する(Upsert
)
オプションupsert: trueを指定した場合
ドキュメントがクエリ条件に一致する場合、
db.collection.update()
は更新を実行します。クエリ条件に一致するドキュメントがない場合、
db.collection.update()
は 1 つのドキュメントを挿入します。注意
複数の同一のアップサートがほぼ同時に発行されると、upsert: true で使用される
update()
によって重複したドキュメントが作成される可能性があります。詳細については、「重複した値を使用したアップサート」を参照してください。
シャーディングされたコレクションで upsert: true
を指定する場合、filter
には完全なシャードキーを含める必要があります。シャーディングされたコレクションにおける追加のdb.collection.update()
動作については、シャーディングされたコレクションを参照してください。
次のタブでは、update()
を使用したupsert
修飾子のさまざまな使用方法を紹介します。
置換ドキュメントのアップサート
クエリ条件に一致するドキュメントがなく、<update>
パラメーターが置換ドキュメント(フィールドと値のペアのみを含むドキュメント)の場合、更新により、置換ドキュメントのフィールドと値を含む新しいドキュメントが挿入されます。
クエリ パラメーターまたは置換ドキュメントのいずれかに
_id
フィールドを指定した場合、MongoDB は、挿入されるドキュメントでその_id
フィールドを使用します。クエリ パラメーターまたは置換ドキュメントのいずれにも
_id
フィールドを指定しない場合、MongoDB は、ランダムに生成された ObjectId 値を持つ_id
フィールドを追加します。注意
クエリ パラメーターと置換ドキュメントで異なる
_id
フィールド値を指定することはできません。指定すると、操作はエラーを返します。
例えば、次の更新では、アップサート オプションが true
に設定されます。
db.books.update( { item: "ZZZ135" }, // Query parameter { $set: { item: "ZZZ135", stock: 5, tags: [ "database" ] // Replacement document } }, { upsert: true } // Options )
<query>
パラメータに一致するドキュメントがない場合、更新操作により、置換ドキュメントのみを含むドキュメントが挿入されます。 置換ドキュメントまたはクエリ ドキュメントでは_id
フィールドが指定されていないため、操作によって新しいドキュメントの_id
フィールドに一意のObjectId
が作成されます。 操作のWriteResultに反映されたupsert
が確認できます。
WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("5da78973835b2f1c75347a83") })
この操作により、次のドキュメントが books
コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。
{ "_id" : ObjectId("5da78973835b2f1c75347a83"), "item" : "ZZZ135", "stock" : 5, "tags" : [ "database" ] }
演算子式を使用してアップサートを実行するようになりました($set
)
クエリ条件に一致するドキュメントがなく、<update>
パラメーターが更新演算子式を含むドキュメントである場合、この操作はでは、<query>
パラメーターの等価句から基本ドキュメントを作成し、<update>
パラメーターの式を適用します。
<query>
からの比較操作は新しいドキュメントに含まれません。 新しいドキュメントに_id
フィールドが含まれていない場合、MongoDB はObjectId値を持つ_id
フィールドを追加します。
例えば、次の更新では、アップサート オプションが true
に設定されます。
db.books.update( { item: "BLP921" }, // Query parameter { // Update document $set: { reorder: false }, $setOnInsert: { stock: 10 } }, { upsert: true } // Options )
クエリ条件に一致するドキュメントがない場合、この操作により次のドキュメントが挿入されます( ObjectId値はそれぞれ異なります)。
{ "_id" : ObjectId("5da79019835b2f1c75348a0a"), "item" : "BLP921", "reorder" : false, "stock" : 10 }
集計パイプラインを使用したアップサート
<update>
パラメーターが 集計パイプライン の場合、更新により、<query>
パラメーターの等価句から基本ドキュメントを作成し、そのドキュメントにパイプラインを適用して挿入するドキュメントを作成します。新しいドキュメントに _id
フィールドが含まれていない場合、MongoDB は ObjectId 値を持つ _id
フィールドを追加します。
たとえば、次のupsert: true操作は、使用する集計パイプラインを指定します
$replaceRoot
ステージ、これは$setOnInsert
更新演算子式と似た動作を提供できます。NOW
集計変数は現在の日時に設定し、$currentDate
更新演算子式と同様の動作を提供できます。
db.books.update( { item: "MRQ014", ratings: [2, 5, 3] }, // Query parameter [ // Aggregation pipeline { $replaceRoot: { newRoot: { $mergeObjects: [ { stock: 0 }, "$$ROOT" ] } } }, { $set: { avgRating: { $avg: "$ratings" }, tags: [ "fiction", "murder" ], lastModified: "$$NOW" } } ], { upsert: true } // Options )
<query>
パラメーターに一致するドキュメントがない場合、この操作により次のドキュメントが books
コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。
{ "_id" : ObjectId("5e2921e0b4c550aad59d1ba9"), "stock" : 0, "item" : "MRQ014", "ratings" : [ 2, 5, 3 ], "avgRating" : 3.3333333333333335, "tags" : [ "fiction", "murder" ], "lastModified" : ISODate("2020-01-23T04:32:32.951Z") }
とupsert
multi
を使用する(一致)
mongosh
から、次のドキュメントをbooks
コレクションに挿入します。
db.books.insertMany( [ { _id: 5, item: "RQM909", stock: 18, info: { publisher: "0000", pages: 170 }, reorder: true }, { _id: 6, item: "EFG222", stock: 15, info: { publisher: "1111", pages: 72 }, reorder: true } ] )
次の操作では、multi
オプションと upsert
オプションの両方を指定します。一致するドキュメントが存在する場合、この操作により一致するすべてのドキュメントが更新されます。一致するドキュメントが存在しない場合は、この操作によって新しいドキュメントが挿入されます。
db.books.update( { stock: { $gte: 10 } }, // Query parameter { // Update document $set: { reorder: false, tags: [ "literature", "translated" ] } }, { upsert: true, multi: true } // Options )
この操作により、一致するすべてのドキュメントが更新され、次の結果になります。
{ "_id" : 5, "item" : "RQM909", "stock" : 18, "info" : { "publisher" : "0000", "pages" : 170 }, "reorder" : false, "tags" : [ "literature", "translated" ] } { "_id" : 6, "item" : "EFG222", "stock" : 15, "info" : { "publisher" : "1111", "pages" : 72 }, "reorder" : false, "tags" : [ "literature", "translated" ] }
とupsert
multi
を使用する(一致なし)
コレクションに一致するドキュメントがない場合、この操作を行うと、<query>
と <update>
の両方の仕様のフィールドを使用して単一のドキュメントが挿入されます。例えば、次の操作について考えてみましょう。
db.books.update( { "info.publisher": "Self-Published" }, // Query parameter { // Update document $set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 } }, { upsert: true, multi: true } // Options )
この操作により、次のドキュメントが books
コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。
{ "_id" : ObjectId("5db337934f670d584b6ca8e0"), "info" : { "publisher" : "Self-Published" }, "reorder" : false, "stock" : 25, "tags" : [ "literature", "hardcover" ] }
ドット_id
クエリによるアップサート
upsert:
true
を指定してupdate()
を実行して、クエリが既存のドキュメントと一致しない場合、クエリがドット表記を使用して _id
フィールドに条件を指定すると、MongoDB は新しいドキュメントの挿入を拒否します。
この制限により、_id
ドキュメントに埋め込まれたフィールドの順序が明確に定義され、クエリで指定された順序に縛られることがなくなります。
この方法でドキュメントを挿入しようとすると、MongoDB でエラーが発生します。例えば、次の更新操作について考えてみましょう。更新操作で upsert:true
を指定し、クエリでドット表記を使用してフィールドに条件を指定しているため、挿入するドキュメントを作成する際にエラーが発生します。
db.collection.update( { "_id.name": "Robert Frost", "_id.uid": 0 }, // Query parameter { $set: { "categories": [ "poet", "playwright" ] // Replacement document } }, { upsert: true } // Options )
WriteResult
操作では、次のエラーが返されます。
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 111, "errmsg" : "field at '_id' must be exactly specified, field at sub-path '_id.name'found" } })
重複した値のアップサート
重複を防ぐためのユニークインデックスがない限り、アップサートによって重複したドキュメントが作成されることがあります。
Andy
という名前のドキュメントが存在せず、複数のクライアントがほぼ同時に次のコマンドを発行する例を考えます。
db.people.update( { name: "Andy" }, { $inc: { score: 1 } }, { upsert: true, multi: true } )
いずれかのクライアントがデータを正常に挿入する前にすべての update()
操作がクエリ フェーズを終了し、かつ name
フィールドにユニークインデックスがない場合、各 update()
操作によって挿入が行われて、name: Andy
を含む複数のドキュメントが作成される可能性があります。
name
フィールドに一意なインデックスを設定すると、ドキュメントが 1 つだけ作成されるようになります。一意なインデックスが設定されると、複数の update()
操作で次の動作が見られるようになります。
正確に 1 つの
update()
操作で新しいドキュメントが正常に挿入されます。その他の
update()
操作は、新しく挿入されたドキュメントを更新するか、一意なキーの競合が原因で失敗します。他の
update()
操作で新しく挿入されたドキュメントを更新するには、次の条件がすべて満たされている必要があります。ターゲット コレクションに一意なインデックスがあるため、重複キー エラーが発生。
更新操作が
updateMany
ではない、またはmulti
がfalse
。アップデートの一致条件は、次のいずれかです。
単一の等価述語。例:
{ "fieldA" : "valueA" }
等価述語の論理 AND。例:
{ "fieldA" : "valueA", "fieldB" : "valueB" }
等価述語内のフィールドが、一意なインデックス キー パターン内のフィールドと一致。
更新操作が、一意なインデックス キー パターン内のフィールドを変更しない。
次の表に示す upsert
操作の例では、キーの衝突が発生した場合に更新されるか失敗します。
ユニークインデックスキーのパターン | アップデート操作 | 結果 | ||||||
---|---|---|---|---|---|---|---|---|
|
| マッチしたドキュメントの score フィールドが 1 インクリメントされます。 | ||||||
|
| 一意なインデックス キー パターン( name )のフィールドが変更されるため、操作は失敗します。 | ||||||
|
| 等式述語フィールド( name 、email )がインデックス キー フィールド(name )と一致しないため、操作は失敗します。 |
集約パイプラインによるアップデート
db.collection.update()
メソッドでは、集計パイプライン [ <stage1>, <stage2>, ... ]
を受け入れて、実行する変更を指定できます。このパイプラインには次のステージが含まれる可能性があります。
$addFields
およびそのエイリアス$set
$replaceRoot
とそのエイリアス$replaceWith
。
集計パイプラインを使用すると、現在のフィールド値に基づいて条件付きのアップデートを表現したり、あるフィールドを他のフィールドの値を使用してアップデートするなど、より表現内容の多いアップデート ステートメントが可能になります。
ドキュメントの他のフィールドの値を使用してフィールドを変更する
次のドキュメントを使用して 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.members.update( { }, [ { $set: { comments: [ "$commentsSemester1", "$commentsSemester2" ], lastUpdate: "$$NOW" } }, { $unset: [ "commentsSemester1", "commentsSemester2" ] } ], { multi: true } )
コマンドの実行後、コレクションには次のドキュメントが含まれます。
{ "_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" ] }
現在のフィールド値に基づいて条件付き更新を実行する
次のドキュメントを使用して 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.update( { }, [ { $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" } } } } ], { multi: true } )
- 第 1 ステージ
$set
段階:- 第 2 ステージ
$set
ステージでは、前のステージで計算されたaverage
フィールドに基づいて新しいフィールドgrade
が計算されます。集計演算子$switch
の詳細については、$switch
を参照してください。
コマンドの実行後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 92, "grade" : "A" } { "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 90, "grade" : "A" } { "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 75, "grade" : "C" }
arrayFilters
配列更新操作に を指定する
アップデート ドキュメントでは、$[<identifier>]
フィルター処理された位置演算子を使用して識別子を定義し、配列フィルター ドキュメントで参照します。識別子がアップデートドキュメントに含まれていない場合、識別子の配列フィルタードキュメントを作成することはできません。
<identifier>
は小文字で始まり、含めることができるのは英数字のみです。
アップデート ドキュメントには同じ識別子を複数回含めることができます。ただし、アップデート ドキュメント内の個別の識別子 ($[identifier]
) それぞれに対し、対応する配列フィルター ドキュメントを 1 つだけ指定する必要があります。つまり、同じ識別子に対して複数の配列フィルター ドキュメントを指定することはできません。たとえば、アップデート ステートメントに識別子 x
が(場合によっては複数回)含まれている場合、x
に 2 つの個別のフィルタ ドキュメントを含む arrayFilters
に対して、次のように指定することはできません。
// INVALID [ { "x.a": { $gt: 85 } }, { "x.b": { $gt: 80 } } ]
ただし、次の例のように、単一のフィルター ドキュメント内の同じ識別子に複合条件を指定できます。
// Example 1 [ { $or: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] } ] // Example 2 [ { $and: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] } ] // Example 3 [ { "x.a": { $gt: 85 }, "x.b": { $gt: 80 } } ]
arrayFilters
は、集計パイプラインが使用される更新では使用できません。
arrayFilters
条件に一致する要素を更新する
指定された条件に一致するすべての配列要素を更新するには、 arrayFiltersパラメーターを使用します。
mongosh
で、次のドキュメントを含む 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.update( { grades: { $gte: 100 } }, { $set: { "grades.$[element]" : 100 } }, { multi: true, arrayFilters: [ { "element": { $gte: 100 } } ] } )
操作後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 100 ] } { "_id" : 3, "grades" : [ 95, 100, 100 ] }
ドキュメントの配列の特定の要素を更新する
また、arrayFilters パラメータを使用して、ドキュメントの配列内の特定のドキュメント フィールドを更新することもできます。
mongosh
で、次のドキュメントを含む 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.update( { }, { $set: { "grades.$[elem].mean" : 100 } }, { multi: true, 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
更新操作に を指定する
mongosh
で、次のドキュメントを含む newStudents
コレクションを作成します。
db.newStudents.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.newStudents.createIndex( { grade: 1 } )
次の更新操作では、インデックス {grade: 1 }
を使用するようにヒントを明示的に示しています。
db.newStudents.update( { points: { $lte: 20 }, grade: "F" }, // Query parameter { $set: { comments1: "failed class" } }, // Update document { multi: true, hint: { grade: 1 } } // Options )
注意
存在しないインデックスを指定した場合、操作はエラーになります。
update コマンドは次を返します。
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
使用されたインデックスを確認するには、次の操作で explain
を実行します。
db.newStudents.explain().update( { "points": { $lte: 20 }, "grade": "F" }, { $set: { "comments1": "failed class" } }, { multi: true, hint: { grade: 1 } } )
db.collection.explain().update()
はドキュメントを変更しません。
変数の使用 let
バージョン 5.0 で追加
コマンド内の他の場所からアクセスできる変数を定義するには let オプションを使用します。
注意
変数を使用して結果をフィルタリングするには、$expr
演算子内の変数にアクセスする必要があります。
コレクション cakeFlavors
を以下ように作成します。
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
次の例では、let
で targetFlavor
変数と newFlavor
変数を定義し、その変数を使用してケーキのフレーバーをチェリーからオレンジに変更します。
db.cakeFlavors.update( { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } }, [ { $set: { flavor: "$$newFlavor" } } ], { let : { targetFlavor: "cherry", newFlavor: "orange" } } )
デフォルトの書込み保証 (write concern) の上書き
次のレプリカセットに対する操作では、w: 2
の書込み保証 (write concern)を指定し、タイムアウトを wtimeout
で5000 ミリ秒に設定しています。この操作は、書き込み (write) がプライマリと1つのセカンダリの両方に伝達された後に返すか、5 秒後にタイムアウトします。
db.books.update( { stock: { $lte: 10 } }, { $set: { reorder: true } }, { multi: true, writeConcern: { w: 2, wtimeout: 5000 } } )
照合の指定
操作に使用する照合を指定します。
照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。
照合オプションの構文は次のとおりです。
collation: { locale: <string>, caseLevel: <boolean>, caseFirst: <string>, strength: <int>, numericOrdering: <boolean>, alternate: <string>, maxVariable: <string>, backwards: <boolean> }
照合を指定する場合、locale
フィールドは必須ですが、その他の照合フィールドはすべて任意です。フィールドの説明については、照合ドキュメントを参照してください。
照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合(db.createCollection()
を参照)には、コレクションの照合が使用されます。
コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。
1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。
mongosh
で、次のドキュメントを含む myColl
という名前のコレクションを作成します。
db.myColl.insertMany( [ { _id: 1, category: "café", status: "A" }, { _id: 2, category: "cafe", status: "a" }, { _id: 3, category: "cafE", status: "a" } ] )
次の操作には照合オプションが付いており、multi
を true
に設定しているので、一致するドキュメントがすべて更新されます。
db.myColl.update( { category: "cafe" }, { $set: { status: "Updated" } }, { collation: { locale: "fr", strength: 1 }, multi: true } )
操作の書込み結果として、コレクション内の 3 つのドキュメントがすべて更新されたことを示す次のドキュメントが返されます。
WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })
操作後、コレクションには次のドキュメントが含まれます。
{ "_id" : 1, "category" : "café", "status" : "Updated" } { "_id" : 2, "category" : "cafe", "status" : "Updated" } { "_id" : 3, "category" : "cafE", "status" : "Updated" }
WriteResult
正常な結果
db.collection.update()
メソッドは、操作のステータスを含む WriteResult()
オブジェクトを返します。成功すると、WriteResult()
オブジェクトには、クエリ条件に一致したドキュメントの数、更新によって挿入されたドキュメントの数、および変更されたドキュメントの数が含まれます。
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
書込み保証 (write concern) エラー
db.collection.update()
メソッドで書込み保証 (write concern) が発生した場合、結果にはWriteResult.writeConcernError
フィールドが含まれます。
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1, "writeConcernError": { "code" : 64, "errmsg" : "waiting for replication timed out", "errInfo" : { "wtimeout" : true, "writeConcern" : { "w" : "majority", "wtimeout" : 100, "provenance" : "getLastErrorDefaults" } } })
次の表は、WriteResult.writeConcernError.provenance
の値について説明したものです。
出所 | 説明 |
---|---|
clientSupplied | 書き込み保証(write concern)がアプリケーションで指定されました。 |
customDefault | 書込み保証 (write concern) は、カスタム定義されたデフォルト値に基づきます。 setDefaultRWConcern を参照してください。 |
getLastErrorDefaults | 書込み保証 (write concern) は、レプリカセットの settings.getLastErrorDefaults のフィールドに基づきます。 |
implicitDefault | 他の書き込み保証(write concern)が一切指定されていない状態で、サーバーから発生した書き込み保証。 |
書込み保証 (write concern) とは関係のないエラー
db.collection.update()
メソッドで書込み保証(write concern)エラーが発生した場合、結果には WriteResult.writeError
フィールドが含まれます。
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 7, "errmsg" : "could not contact primary for replica set shard-a" } })