db.collection.findAndModify()
MongoDB とドライバー
このページでは、 mongosh
メソッドについて説明します。MongoDB ドライバーで同等のメソッドを確認するには、ご使用のプログラミング言語の対応するページを参照してください。
定義
互換性
このメソッドは、次の環境でホストされている配置で使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
注意
このコマンドは、すべての MongoDB Atlas クラスターでサポートされています。すべてのコマンドに対する Atlas のサポートについては、「サポートされていないコマンド」を参照してください。
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
バージョン 5.0 での変更。
findAndModify()
メソッドの形式は次のとおりです。
db.collection.findAndModify({ query: <document>, sort: <document>, remove: <boolean>, update: <document or aggregation pipeline>, new: <boolean>, fields: <document>, upsert: <boolean>, bypassDocumentValidation: <boolean>, writeConcern: <document>, maxTimeMS: <integer>, collation: <document>, arrayFilters: [ <filterdocument1>, ... ], let: <document> // Added in MongoDB 5.0 });
db.collection.findAndModify()
メソッドは、次の埋め込みドキュメント フィールドを持つドキュメント パラメータを受け取ります。
Parameter | タイプ | 説明 | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
query | ドキュメント | 任意。変更の選択基準。 指定しない場合、デフォルトは空のドキュメントになります。 クエリ引数がドキュメントでない場合、操作はエラーになります。 | ||||||||||||||||||
| ドキュメント | 任意。クエリで複数のドキュメントが選択された場合に、その操作で更新するドキュメントを決定します。 ソート引数がドキュメントでない場合、操作はエラーになります。 MongoDB では、コレクション内のドキュメントを特定の順序で保存することはありません。重複する値を含むフィールドでソートする場合、それらの値を含むドキュメントは任意の順序で返されます。 一貫したソート順序が必要な場合は、一意の値を含むフィールドを少なくとも 1 つ含めてソートしてください。これを保証する最も簡単な方法は、 詳細については、「ソートの整合性」を参照してください。 | ||||||||||||||||||
remove | ブール値 | remove フィールドまたは update フィールドのいずれかを指定する必要があります。query フィールドで指定されたドキュメントを削除します。選択したドキュメントを削除するには、これを true に設定します。デフォルト値は false です。 | ||||||||||||||||||
update | ドキュメントまたは配列 |
| ||||||||||||||||||
new | ブール値 | 任意。 true の場合、元のドキュメントではなく更新されたドキュメントを返します。デフォルト値は false です。 | ||||||||||||||||||
fields | ドキュメント | 任意。返すフィールドのサブセット。
プロジェクションの詳細については、「 | ||||||||||||||||||
upsert | ブール値 | 任意。
複数のアップサートを回避するため、 デフォルトは | ||||||||||||||||||
bypassDocumentValidation | ブール値 | 任意。 操作中に db.collection.findAndModify() がドキュメント検証をバイパスできるようにします。 これにより、検証要件を満たさないドキュメントを更新できるようになります。 | ||||||||||||||||||
writeConcern | ドキュメント | 任意。書込み保証(write concern)を表現するドキュメント。デフォルトの書込み保証を使用する場合は省略します。 トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。 | ||||||||||||||||||
maxTimeMS | non-negative integer | 任意。 時間制限をミリ秒単位で指定します。 MongoDB は、 | ||||||||||||||||||
collation | ドキュメント | 任意。 操作に使用する照合を指定します。 照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。 照合オプションの構文は次のとおりです。
照合を指定する場合、 照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合( コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。 1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。 | ||||||||||||||||||
arrayFilters | 配列 | 任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。 アップデート ドキュメントでは、
アップデート ドキュメントには同じ識別子を複数回含めることができます。ただし、アップデート ドキュメント内の個別の識別子 (
ただし、次の例のように、単一のフィルター ドキュメント内の同じ識別子に複合条件を指定できます。
例については、「配列更新オペレーションでの
| ||||||||||||||||||
ドキュメント | 任意。 変数のリストを含むドキュメントを指定します。これにより、変数をクエリテキストから分離することで、コマンドの読みやすさを向上させることができます。 ドキュメントの構文は次のとおりです。
変数は式によって返された値に設定され、その後は変更できません。 コマンド内の変数の値にアクセスするには、二重ドル記号の接頭辞( 結果のフィルタリングに変数を使用するには、
バージョン 5.0 で追加 |
Return Data
削除操作では、クエリがドキュメントと一致する場合、 findAndModify()
は削除されたドキュメントを返します。クエリが削除するドキュメントと一致しない場合、 findAndModify()
null
を返します。
更新操作の場合、 findAndModify()
次のいずれかを返します。
new
パラメーターがセットされていないか、false
の場合クエリがドキュメントにマッチした場合、変更前のドキュメント。
それ以外の場合は、
null
。
new
がtrue
の場合クエリが一致を返した場合、更新されたドキュメント。
upsert: true
でクエリに一致するドキュメントがない場合、挿入されたドキュメント。それ以外の場合は、
null
。
動作
パフォーマンス
再試行可能な書き込みでは、更新を実行する前に、findAndModify()
メソッドを使用してドキュメント全体をレプリカセット内の各ノードの特別なサイドコレクションにコピーする必要があります。そのため、大きな文書や大きなレプリカセットを扱う場合、findAndModify()
はコストが大きい操作になる可能性があります。
バージョン 8.0 の新機能 :ユーザー定義の順序付けで最初のドキュメントをより優れたパフォーマンスで更新するため、sort
オプションを指定した db.collection.updateOne()
メソッドを使用します。
fields
プロジェクション
重要
言語の整合性
find()
と findAndModify()
のプロジェクションを集計の $project
ステージと一貫性を持たせるために、
find()
およびfindAndModify()
プロジェクションは集計と構文を受け付けます。MongoDB は、プロジェクションに関して追加の制限を適用します。詳細については、「プロジェクションの制限」を参照してください。
fields
オプションは次のような形式のドキュメントを取ります:
{ field1: <value>, field2: <value> ... }
プロジェクション | 説明 |
---|---|
<field>: <1 or true> | フィールドを包含することを指定します。プロジェクションの値としてゼロ以外の整数を指定した場合、その値を true として処理します。 |
<field>: <0 or false> | フィールドの除外を指定します。 |
"<field>.$": <1 or true> | |
<field>: <array projection> | 配列プロジェクション 演算子( ビューには使用できません。 |
<field>: <aggregation expression> | プロジェクションを行ったフィールドの値を指定します。 集計式と構文の使用(リテラルと集計変数の使用を含む)では、新しいフィールドをプロジェクションしたり、既存のフィールドを新しい値でプロジェクションしたりできます。
|
埋め込みフィールド仕様
埋め込みドキュメント内のフィールドの場合は、次のいずれかを使用してフィールドを指定できます。
ドット表記の場合は次のようになります。
"field.nestedfield": <value>
ネストされた形式の例
{ field: { nestedfield: <value> } }
_id
フィールドプロジェクション
_id
フィールドは、プロジェクションで _id: 0
を明示的に指定して抑制しない限り、返されるドキュメントにデフォルトで含まれます。
包含または除外
projection
には、 _id
フィールドを除いて、包含指定と除外指定の両方を含めることはできません。
フィールドを明示的に含めるプロジェクションでは、
_id
フィールドだけが明示的に除外できる唯一のフィールドです。フィールドを明示的に除外するプロジェクションでは、
_id
フィールドが明示的に包含できる唯一のフィールドですが、デフォルトで_id
フィールドが含まれます。
プロジェクションの詳細については、以下も参照してください。
一意なインデックスを使用したアップサート
重複を防ぐためのユニークインデックスがない限り、アップサートによって重複したドキュメントが作成されることがあります。
Andy
という名前のドキュメントが存在せず、複数のクライアントがほぼ同時に次のコマンドを発行する例を考えます。
db.people.findAndModify( { query: { name: "Andy" }, update: { $inc: { score: 1 } }, upsert: true } )
クライアントがデータを正常に挿入する前にすべてのfindOneAndUpdate()
操作がクエリ フェーズを終了し、かつname
フィールドに一意なインデックスがない場合、各findOneAndUpdate()
操作によって挿入が行われ、name: Andy
を含む複数のドキュメントが作成される可能性があります。
name
フィールドに一意なインデックスを設定すると、ドキュメントが 1 つだけ作成されるようになります。一意なインデックスが設定されると、複数のfindOneAndUpdate()
操作で次の動作が見られるようになります。
正確に 1 回の
findOneAndUpdate()
操作で新しいドキュメントが正常に挿入されます。その他の
findOneAndUpdate()
操作は、新しく挿入されたドキュメントを更新するか、一意なキーの競合が原因で失敗します。他の
findOneAndUpdate()
操作で新しく挿入されたドキュメントを更新するには、次の条件がすべて満たされている必要があります。ターゲット コレクションに一意なインデックスがあるため、重複キー エラーが発生。
更新操作が
updateMany
ではない、またはmulti
がfalse
。アップデートの一致条件は、次のいずれかです。
単一の等価述語。例:
{ "fieldA" : "valueA" }
等価述語の論理 AND。例:
{ "fieldA" : "valueA", "fieldB" : "valueB" }
等価述語内のフィールドが、一意なインデックス キー パターン内のフィールドと一致。
更新操作が、一意なインデックス キー パターン内のフィールドを変更しない。
次の表に示す upsert
操作の例では、キーの衝突が発生した場合に更新されるか失敗します。
ユニークインデックスキーのパターン | アップデート操作 | 結果 | ||||||
---|---|---|---|---|---|---|---|---|
|
| マッチしたドキュメントの score フィールドが 1 インクリメントされます。 | ||||||
|
| 一意なインデックス キー パターン( name )のフィールドが変更されるため、操作は失敗します。 | ||||||
|
| 等式述語フィールド( name 、email )がインデックス キー フィールド(name )と一致しないため、操作は失敗します。 |
シャーディングされたコレクション
シャーディングされたコレクションでfindAndModify
を使用するには、
1つのシャードのみをターゲットにする場合は、
query
フィールドで部分的なシャードキーを使用できます。またはquery
フィールドの完全なシャードキーに等価条件を指定できます。バージョン7.1以降では、クエリ仕様でシャードキーまたは
_id
フィールドを指定する必要がありません。
シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。シャードキーがないドキュメントをターゲットにするには、null
等価一致を別のフィルター条件(_id
フィールドなど)と組み合わせて使用できます。以下に例を挙げます。
{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key
シャードキーの変更
シャードキー フィールドが不変の _id
フィールドでない限り、ドキュメントのシャードキー値を更新できます。
警告
シャーディングされたコレクション内のドキュメントには、シャード キー フィールドがないことがあります。ドキュメントのシャード キーの値を変更するときに、誤ってシャード キーを削除しないように注意してください。
既存のシャードキー値をdb.collection.findAndModify()
で更新する方法:
必ず
mongos
上で使用します。シャードに直接操作を実行しないでください。トランザクション内で、または 再試行可能な書き込みとして実行する必要があります。
完全なシャードキーに等価フィルターを含める必要があります。
欠落しているシャードキー
シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。db.collection.findAndModify()
を使用してドキュメントにないシャードキーを設定するには、以下が必要です。
必ず
mongos
上で使用します。シャードに直接操作を実行しないでください。新しいシャードキー値が
null
でない場合は、トランザクション内で実行するか、再試行可能な書き込みとして実行する必要があります。完全なシャードキーに等価フィルターを含める必要があります。
Tip
欠落しているキー値は NULL 等価一致の一部として返されるため、NULL 値のキーが更新されないように、必要に応じて追加のクエリ条件(_id
フィールドなど)を追加します。
以下も参照してください。
ドキュメントの検証
db.collection.findAndModify()
メソッドはbypassDocumentValidation
オプションのサポートを追加します。これにより、検証ルールを使用してコレクションにドキュメントを挿入または更新するときにドキュメント検証をバイパスできます。
update
メソッドとの比較
ドキュメントを更新する場合の db.collection.findAndModify()
メソッドと updateOne()
メソッドの動作は異なります。
更新条件に一致するドキュメントが複数ある場合、
db.collection.findAndModify()
では、sort
を指定することで、更新するドキュメントの選択に関して一定の制御が可能です。updateOne()
は一致する最初のドキュメントを更新します。デフォルトでは、
db.collection.findAndModify()
はドキュメントの変更前のバージョンを返します。 更新済みのドキュメントを取得するには、new
オプションを使用します。updateOne()
メソッドは、操作のステータスを含むWriteResult()
オブジェクトを返します。更新されたドキュメントを返すには、
find()
メソッドを使用します。ただし、更新してからドキュメントを取得するまでの間に、他の更新によってドキュメントが変更される可能性があります。また、更新によって 1 つのドキュメントのみが変更されたが、複数のドキュメントが一致した場合は、更新されたドキュメントを識別するために追加のロジックを使用する必要があります。
1 つのドキュメントを変更する場合、db.collection.findAndModify()
メソッドと updateOne()
メソッドの両方でドキュメントがアトミックに更新されます。これらのメソッドの相互作用と操作順序の詳細については、「アトミック性とトランザクション」を参照してください。
トランザクション
db.collection.findAndModify()
は分散トランザクション内で使用できます。
重要
ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。
トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。
トランザクション内のアップサート
トランザクションがクロスシャード間書き込みトランザクション(write transaction)でない場合に、分散トランザクション内にコレクションとインデックスを作成できます。
db.collection.findAndModify()
と upsert: true
は、既存のコレクションまたは存在しないコレクションで実行できます。存在しないコレクションに対して実行すると、操作によってコレクションが作成されます。
書込み保証とトランザクション
トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。
Oplog エントリ
db.collection.findAndModify()
操作によってドキュメントが正常に検出され、変更された場合、その操作によってoplog(操作ログ)にエントリが追加されます。操作が失敗した場合、または更新するドキュメントが見つからなかった場合は、その操作によって oplog にエントリーが追加されることはありません。
例
更新と返却
次のメソッドは、クエリの条件に一致するドキュメントの people コレクション内の既存のドキュメントを更新して返します。
db.people.findAndModify({ query: { name: "Tom", state: "active", rating: { $gt: 10 } }, sort: { rating: 1 }, update: { $inc: { score: 1 } } })
このメソッドは、次のアクションを実行します。
query
は、name
フィールドの値がTom
、state
フィールドの値がactive
、rating
フィールドの値がgreater than
10 であるドキュメントをpeople
コレクション内で検索します。sort
は、クエリの結果を昇順に並べます。複数のドキュメントがquery
条件を満たす場合、メソッドはこのsort
の順序に従って最初のドキュメントを変更対象として選択します。increments
により、score
フィールドの値が 1 だけ更新されます。このメソッドは元の(つまり 変更前の)このアップデート用に選択されたドキュメントを返します。
{ "_id" : ObjectId("50f1e2c99beb36a0f45c6453"), "name" : "Tom", "state" : "active", "rating" : 100, "score" : 5 } 更新されたドキュメントを返すには、メソッドに
new:true
オプションを追加します。query
条件に一致するドキュメントがない場合、メソッドはnull
を返します。
アップサート
次のメソッドには、update
操作にupsert: true
のオプションが含まれおり、一致するドキュメントをアップデートするか、一致するドキュメントが存在しない場合は新しいドキュメントを作成します。
db.people.findAndModify({ query: { name: "Gus", state: "active", rating: 100 }, sort: { rating: 1 }, update: { $inc: { score: 1 } }, upsert: true })
一致するドキュメントが見つかった場合、更新を実行します。
メソッドが一致するドキュメントを見つけられない場合、メソッドは新しいドキュメントを作成します。このメソッドには sort
オプションが含まれていたため、元の(変更前の)ドキュメントとして空のドキュメント { }
が返されます。
{ }
メソッドに sort
オプションが含まれていない場合、メソッドは null
を返します。
null
新しいドキュメントの返却
次のメソッドには、 upsert: true
オプションとnew:true
オプションの両方が含まれています。このメソッドは、一致するドキュメントを更新して更新されたドキュメントを返すか、一致するドキュメントが存在しない場合はドキュメントを挿入して value
フィールドに新しく挿入されたドキュメントを返します。
次の例では、people
コレクション内のどのドキュメントも query
条件に一致しません。
db.people.findAndModify({ query: { name: "Pascal", state: "active", rating: 25 }, sort: { rating: 1 }, update: { $inc: { score: 1 } }, upsert: true, new: true })
このメソッドは、新しく挿入されたドキュメントを返します。
{ "_id" : ObjectId("50f49ad6444c11ac2448a5d6"), "name" : "Pascal", "rating" : 25, "score" : 1, "state" : "active" }
並べ替えと削除
次の例では、rating
フィールドに sort
仕様を含めることで、state
の値が active
であり、一致するドキュメントの中で最も rating
が低い 1 つのドキュメントを people
コレクションから削除します。
db.people.findAndModify( { query: { state: "active" }, sort: { rating: 1 }, remove: true } )
このメソッドは、削除されたドキュメントを返します。
{ "_id" : ObjectId("52fba867ab5fdca1299674ad"), "name" : "XYZ123", "score" : 1, "state" : "active", "rating" : 3 }
照合の指定
照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。
コレクション myColl
は、次のドキュメントを含みます。
{ _id: 1, category: "café", status: "A" } { _id: 2, category: "cafe", status: "a" } { _id: 3, category: "cafE", status: "a" }
次の操作には照合オプションが含まれます。
db.myColl.findAndModify({ query: { category: "cafe", status: "a" }, sort: { category: 1 }, update: { $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.findAndModify()
メソッド内でarrayFilters
オプションとともに使用します。
db.students.findAndModify({ query: { grades: { $gte: 100 } }, update: { $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.findAndModify({ query: { _id : 1 }, update: { $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.findAndModify()
は、更新の集計パイプラインを受け入れることができます。このパイプラインには次のステージが含まれる可能性があります。
$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.findAndModify( { query: { "_id" : 1 }, update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ], // The $set stage is an alias for ``$addFields`` stage new: true } )
この操作は更新されたドキュメントを返します。
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ], "total" : 250 }
変数の使用 let
バージョン 5.0 で追加
コマンド内の他の場所からアクセスできる変数を定義するには let オプションを使用します。
注意
変数を使用して結果をフィルタリングするには、$expr
演算子内の変数にアクセスする必要があります。
コレクション cakeFlavors
を以下ように作成します。
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
次の例では、let
に targetFlavor
変数を定義し、その変数を使用してケーキのフレーバーをチェリーからオレンジに変更します。
db.cakeFlavors.findAndModify( { query: { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } }, update: { flavor: "orange" }, let: { targetFlavor: "cherry" } } )
ユーザーロールとドキュメントの更新
MongoDB 7.0 以降では、新しい USER_ROLES
システム変数を使用してユーザー ロールを返すことができます。
このセクションの例では、医療情報を含むコレクション内のフィールドの更新を示します。この例では、USER_ROLES
システム変数から現在のユーザー ロールを読み取り、ユーザーが特定のロールを持っている場合にのみ更新を実行します。
システム変数を使用するには、変数名の先頭に $$
を追加します。システム変数 USER_ROLES
を $$USER_ROLES
として指定します。
この例では、次のユーザーを作成します。
James
Billing
ロールの使用Michelle
Provider
ロールの使用
ロール、ユーザー、コレクションを作成するには、次の手順を実行します。
ロールの作成
必要な権限とリソースを持つ Billing
および Provider
という名前のロールを作成します。
実行:
db.createRole( { role: "Billing", privileges: [ { resource: { db: "test", collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } ) db.createRole( { role: "Provider", privileges: [ { resource: { db: "test", collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } )
Provider
ロールを持つ Michelle
としてログインし、更新を実行します。
更新の実行
実行:
// Attempt to find and modify document db.medical.findAndModify( { query: { $and: [ { // Only update the document for Mary Smith patientName: { $eq: "Mary Smith" } }, { // User must have the Provider role to perform the update $expr: { $ne: [ { $setIntersection: [ [ "Provider" ], "$$USER_ROLES.role" ] }, [] ] } } ] }, // Update document update: { patientName: "Mary Smith", diagnosisCode: "ACH 03", creditCard: "6541-7534-9637-3456" } } )
前の例では、$setIntersection
を使用して、"Provider"
s文字列と $$USER_ROLES.role
のユーザー ロールの共通部分が空ではないドキュメントを返します。Michelle
はProvider
のロールを持つので、更新が実行されます。
次に、Provider
ロールを持たない James
としてログインし、同じ更新の実行を試みます。
更新の試行
実行:
// Attempt to find and modify document db.medical.findAndModify( { query: { $and: [ { // Only update the document for Mary Smith patientName: { $eq: "Mary Smith" } }, { // User must have the Provider role to perform the update $expr: { $ne: [ { $setIntersection: [ [ "Provider" ], "$$USER_ROLES.role" ] }, [] ] } } ] }, // Update document update: { patientName: "Mary Smith", diagnosisCode: "ACH 03", creditCard: "6541-7534-9637-3456" } } )
前の例では、ドキュメントは更新されません。