db.collection.findOneAndUpdate()
MongoDB とドライバー
このページでは、 mongosh
メソッドについて説明します。MongoDB ドライバーで同等のメソッドを確認するには、ご使用のプログラミング言語の対応するページを参照してください。
定義
db.collection.findOneAndUpdate( filter, update, options )
filter
およびsort
条件に基づいて単一のドキュメントを更新します。Tip
バージョン 8.0 の新機能 :
updateOne()
メソッドには、ユーザーが指定したソート順で最初のドキュメントを更新するsort
オプションが含まれています。次の値を返します。 デフォルトでは元のドキュメントを返します。returnNewDocument が true
に設定されているか returnDocument がafter
に設定されている場合、更新されたドキュメントを返します。
互換性
このメソッドは、次の環境でホストされている配置で使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
注意
このコマンドは、すべての MongoDB Atlas クラスターでサポートされています。すべてのコマンドに対する Atlas のサポートについては、「サポートされていないコマンド」を参照してください。
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
findOneAndUpdate()
メソッドの形式は次のとおりです。
db.collection.findOneAndUpdate( <filter>, <update document or aggregation pipeline>, { writeConcern: <document>, projection: <document>, sort: <document>, maxTimeMS: <number>, upsert: <boolean>, returnDocument: <string>, returnNewDocument: <boolean>, collation: <document>, arrayFilters: [ <filterdocument1>, ... ] } )
findOneAndUpdate()
メソッドは次のパラメーターを取ります。
Parameter | タイプ | 説明 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ドキュメント | |||||||||||||||||||
| ドキュメントまたは配列 | 更新ドキュメントまたは集計パイプライン。
| ||||||||||||||||||
| ドキュメント | 任意。書込み保証(write concern)を表現するドキュメント。デフォルトの書込み保証を使用する場合は省略します。
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。 | ||||||||||||||||||
| ドキュメント | 任意。返すフィールドのサブセット。 返されたドキュメント内のすべてのフィールドを返すには、このパラメーターを省略します。 プロジェクションの引数がドキュメントでない場合、操作はエラーになります。 | ||||||||||||||||||
| ドキュメント | |||||||||||||||||||
| 数値 | 任意。 操作が 以内に完了する必要がある制限時間をミリ秒単位で指定します。 制限を超えた場合はエラーがスローされます。 | ||||||||||||||||||
| ブール値 | 任意。
複数のアップサートを回避するため、 デフォルトは | ||||||||||||||||||
| string | 任意。
| ||||||||||||||||||
| ブール値 | 任意。 デフォルトは | ||||||||||||||||||
| ドキュメント | 任意。 操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。
照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 | ||||||||||||||||||
| 配列 | 任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。 アップデート ドキュメントでは、
アップデート ドキュメントには同じ識別子を複数回含めることができます。ただし、アップデート ドキュメント内の個別の識別子 (
ただし、次の例のように、単一のフィルター ドキュメント内の同じ識別子に複合条件を指定できます。
例については、「 を使用した配列更新操作
|
動作
パフォーマンス
再試行可能な書き込みでは、更新を実行する前に、findOneAndUpdate()
メソッドを使用してドキュメント全体をレプリカセット内の各ノードの特別なサイドコレクションにコピーする必要があります。そのため、大きな文書や大きなレプリカセットを扱う場合、findOneAndUpdate()
はコストが大きい操作になる可能性があります。
バージョン 8.0 の新機能 :ユーザー定義の順序付けで最初のドキュメントをより優れたパフォーマンスで更新するため、sort
オプションを指定した db.collection.updateOne()
メソッドを使用します。
ドキュメント一致
db.collection.findOneAndUpdate()
は、 filter
に一致するコレクション内の最初に一致するドキュメントを更新します。filter
に一致するドキュメントがない場合、ドキュメントは更新されません。
sort
パラメータを使用して、どのドキュメントを更新するかを制御することができます。
プロジェクション
重要
言語の整合性
find()
とfindAndModify()
のプロジェクションを集計の$project
ステージと一貫性を持たせるために、
find()
とfindAndModify()
のプロジェクションは集計式と構文 を受け付けます。MongoDB は、プロジェクションに関して追加の制限を適用します。詳細については、「プロジェクションの制限」を参照してください。
projection
パラメータは次の形式のドキュメントを取ります。
{ field1 : <value>, field2 : <value> ... }
プロジェクション | 説明 |
---|---|
| フィールドを包含することを指定します。プロジェクションの値としてゼロ以外の整数を指定した場合、その値を |
| フィールドの除外を指定します。 |
| |
| 配列プロジェクション 演算子( ビューには使用できません。 |
| プロジェクションを行ったフィールドの値を指定します。 集計式と構文の使用(リテラルと集計変数の使用を含む)では、新しいフィールドをプロジェクションしたり、既存のフィールドを新しい値でプロジェクションしたりできます。
|
埋め込みフィールド仕様
埋め込みドキュメント内のフィールドの場合は、次のいずれかを使用してフィールドを指定できます。
ドット表記の場合は次のようになります。
"field.nestedfield": <value>
ネストされた形式の例
{ field: { nestedfield: <value> } }
_id
フィールドプロジェクション
_id
フィールドは、プロジェクションで _id: 0
を明示的に指定して抑制しない限り、返されるドキュメントにデフォルトで含まれます。
包含または除外
projection
には、 _id
フィールドを除いて、包含指定と除外指定の両方を含めることはできません。
フィールドを明示的に含めるプロジェクションでは、
_id
フィールドだけが明示的に除外できる唯一のフィールドです。フィールドを明示的に除外するプロジェクションでは、
_id
フィールドが明示的に包含できる唯一のフィールドですが、デフォルトで_id
フィールドが含まれます。
プロジェクションの詳細については、以下も参照してください。
シャーディングされたコレクション
シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。シャードキーがないドキュメントをターゲットにするには、null
等価一致を別のフィルター条件(_id
フィールドなど)と組み合わせて使用できます。以下に例を挙げます。
{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key
シャードキーの変更
シャードキー フィールドが不変の _id
フィールドでない限り、ドキュメントのシャードキー値を更新できます。
警告
シャーディングされたコレクション内のドキュメントには、シャード キー フィールドがないことがあります。ドキュメントのシャード キーの値を変更するときに、誤ってシャード キーを削除しないように注意してください。
既存のシャードキー値をdb.collection.findOneAndUpdate()
で変更するには
必ず
mongos
上で使用します。シャードに直接操作を実行しないでください。トランザクション内で、または 再試行可能な書き込みとして実行する必要があります。
完全なシャードキーに等価フィルターを含める必要があります。
欠落しているシャードキー
シャーディングされたコレクション内のドキュメントには、 シャードキー フィールドがない場合があります 。 To use db.collection.findOneAndUpdate()
to set the document's missing shard key,
必ず
mongos
上で使用します。シャードに直接操作を実行しないでください。新しいシャードキー値が
null
でない場合は、トランザクション内で実行するか、再試行可能な書き込みとして実行する必要があります。完全なシャードキーに等価フィルターを含める必要があります。
Tip
欠落しているキー値は NULL 等価一致の一部として返されるため、NULL 値のキーが更新されないように、必要に応じて追加のクエリ条件(_id
フィールドなど)を追加します。
以下も参照してください。
トランザクション
db.collection.findOneAndUpdate()
は分散トランザクション内で使用できます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
トランザクション内のアップサート
トランザクションがクロスシャード間書き込みトランザクション(write transaction)でない場合に、分散トランザクション内にコレクションとインデックスを作成できます。
db.collection.findOneAndUpdate()
と upsert: true
は、既存のコレクションまたは存在しないコレクションで実行できます。存在しないコレクションに対して実行すると、操作によってコレクションが作成されます。
書込み保証とトランザクション
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
Oplog エントリ
db.collection.findOneAndUpdate()
操作によってドキュメントが正常に更新されると、その操作によって oplog(操作ログ)にエントリーが追加されます。操作が失敗した場合、または更新するドキュメントが見つからなかった場合は、その操作によって oplog にエントリーが追加されることはありません。
例
ドキュメントの更新
grades
コレクションには、以下と同様のドキュメントが含まれています。
{ _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 }, { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 }, { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 }, { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 }, { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 }, { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
次の操作では、name : R. Stiles
にある最初のドキュメントを検索し、スコアを5
増加させます。
db.grades.findOneAndUpdate( { "name" : "R. Stiles" }, { $inc: { "points" : 5 } } )
この操作は、更新前のオリジナルドキュメントを返します。
{ _id: 6319, name: "R. Stiles", "assignment" : 2, "points" : 12 }
returnNewDocument
が true の場合、操作は代わりに更新されたドキュメントを返します。
ドキュメントのソートと更新
grades
コレクションには、以下と同様のドキュメントが含まれています。
{ _id: 6305, name : "A. MacDyver", "assignment" : 5, "points" : 24 }, { _id: 6308, name : "B. Batlock", "assignment" : 3, "points" : 22 }, { _id: 6312, name : "M. Tagnum", "assignment" : 5, "points" : 30 }, { _id: 6319, name : "R. Stiles", "assignment" : 2, "points" : 12 }, { _id: 6322, name : "A. MacDyver", "assignment" : 2, "points" : 14 }, { _id: 6234, name : "R. Stiles", "assignment" : 1, "points" : 10 }
次の操作では、name : "A. MacDyver"
にあるドキュメントを更新します。この操作では、一致するドキュメントを points
の昇順でソートし、最もポイントが少ない一致するドキュメントを更新します。
db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort : { "points" : 1 } } )
この操作は、更新前のオリジナルドキュメントを返します。
{ _id: 6322, name: "A. MacDyver", "assignment" : 2, "points" : 14 }
返されたドキュメントのプロジェクション
次の操作では、プロジェクションを使用して、返されたドキュメントの _id
、points
、assignment
フィールドのみを表示します。
db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort : { "points" : 1 }, projection: { "assignment" : 1, "points" : 1 } } )
この操作は、projection
ドキュメントで指定されたフィールドと、プロジェクション ドキュメントで明示的に非表示にされていない(_id: 0
)_id
フィールドのみを含む元のドキュメントを返します。
{ "_id" : 6322, "assignment" : 2, "points" : 14 }
時間制限のあるドキュメントの更新
次の操作では、更新を完了するために 5 ミリ秒の時間制限が設定されます。
try { db.grades.findOneAndUpdate( { "name" : "A. MacDyver" }, { $inc : { "points" : 5 } }, { sort: { "points" : 1 }, maxTimeMS : 5 }; ); } catch(e){ print(e); }
操作が時間制限を超えた場合、以下が返されます。
Error: findAndModifyFailed failed: { "ok" : 0, "errmsg" : "operation exceeded time limit", "code" : 50 }
アップサートによるドキュメント更新
次の操作では、filter
に一致するものがない場合に、upsert
フィールドを使用して更新ドキュメントを挿入します。
try { db.grades.findOneAndUpdate( { "name" : "A.B. Abracus" }, { $set: { "name" : "A.B. Abracus", "assignment" : 5}, $inc : { "points" : 5 } }, { sort: { "points" : 1 }, upsert:true, returnNewDocument : true } ); } catch (e){ print(e); }
この操作では、以下を返します。
{ "_id" : ObjectId("5789249f1c49e39a8adc479a"), "name" : "A.B. Abracus", "assignment" : 5, "points" : 5 }
returnNewDocument
が false の場合、返す元のドキュメントがないため、操作ではnull
を返します。
照合の指定
照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。
コレクション myColl
は、次のドキュメントを含みます。
{ _id: 1, category: "café", status: "A" } { _id: 2, category: "cafe", status: "a" } { _id: 3, category: "cafE", status: "a" }
次の操作には照合オプションが含まれます。
db.myColl.findOneAndUpdate( { category: "cafe" }, { $set: { status: "Updated" } }, { collation: { locale: "fr", strength: 1 } } );
この操作を実行すると次のドキュメントが返されます。
{ "_id" : 1, "category" : "café", "status" : "A" }
次を使用して配列更新操作を行います: arrayFilters
注意
arrayFilters
は、集計パイプラインが使用される更新では使用できません。
配列フィールドを更新するときに、どの配列要素を更新するかを決定するための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>]
をdb.collection.findOneAndUpdate()
メソッドでarrayFilters
オプションとともに使用します。
db.students.findOneAndUpdate( { grades: { $gte: 100 } }, { $set: { "grades.$[element]" : 100 } }, { arrayFilters: [ { "element": { $gte: 100 } } ] } )
この操作により 1 つのドキュメントの grades
フィールドが更新され、操作後にコレクションには次のドキュメントが含まれます。
{ "_id" : 1, "grades" : [ 95, 92, 90 ] } { "_id" : 2, "grades" : [ 98, 100, 100 ] } { "_id" : 3, "grades" : [ 95, 110, 100 ] }
ドキュメントの配列の特定の要素を更新する
注意
arrayFilters
は、集計パイプラインが使用される更新では使用できません。
次のドキュメントを使用してコレクション 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 } ] } ] )
次の操作では、_id
フィールドが 1
に等しいドキュメントを検索し、フィルター処理された位置演算子 $[<identifier>]
を arrayFilters
とともに使用して、grades
配列内で grade が 85
以上の全要素の mean
を変更します。
db.students2.findOneAndUpdate( { _id : 1 }, { $set: { "grades.$[elem].mean" : 100 } }, { arrayFilters: [ { "elem.grade": { $gte: 85 } } ] } )
この操作により 1 つのドキュメントの grades
フィールドが更新され、操作後にコレクションには次のドキュメントが含まれます。
{ "_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" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] }
更新に集計パイプラインを使用
db.collection.findOneAndUpdate()
は、更新の集計パイプラインを受け入れることができます。このパイプラインには次のステージが含まれる可能性があります。
$addFields
およびそのエイリアス$set
$replaceRoot
とそのエイリアス$replaceWith
。
集計パイプラインを使用すると、現在のフィールド値に基づいて条件付きのアップデートを表現したり、あるフィールドを他のフィールドの値を使用してアップデートするなど、より表現内容の多いアップデート ステートメントが可能になります。
たとえば、次のドキュメントを含むコレクション 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 } ] } ] )
次の操作では、_id
フィールドが 1
に等しいドキュメントを検索し、集計パイプラインを使用して grades
フィールドから新しいフィールド total
を計算します。
db.students2.findOneAndUpdate( { _id : 1 }, [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage { returnNewDocument: true } )
この操作では更新されたドキュメントを返します。
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" :85, "std" : 6 } ], "total" : 250 }