Docs Menu
Docs Home
/
MongoDBマニュアル
/ / /

db.collection.findAndModify()

項目一覧

  • 定義
  • 互換性
  • 構文
  • Return Data
  • 動作

MongoDB とドライバー

このページでは、 mongosh メソッドについて説明します。MongoDB ドライバーで同等のメソッドを確認するには、ご使用のプログラミング言語の対応するページを参照してください。

C#Java SyncNode.jsPyMongoCC++GoJava RSKotlin CoroutineKotlin SyncPHPMongoidRustScala
db.collection.findAndModify(document)

重要

非推奨の mongosh メソッド

代わりに findOneAndUpdate()findOneAndDelete()、または findOneAndReplace() を使用します。

1 つのドキュメントを更新して返します。デフォルトでは、返されるドキュメントには更新時に行われた変更は含まれません。更新時に行われた変更を含むドキュメントを返すには、 newオプションを使用します。

次の環境でホストされる配置には db.collection.findAndModify() を使用できます。

  • MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです

  • 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
ドキュメント

任意。変更の選択基準。query フィールドでは、db.collection.find() メソッドで使用されるのと同じ クエリ セレクターが使用されます。クエリは複数のドキュメントと一致することがありますが、db.collection.findAndModify() により更新対象のドキュメントが 1 件だけ選択されます

指定しない場合、デフォルトは空のドキュメントになります。

クエリ引数がドキュメントでない場合、操作はエラーになります。

sort

ドキュメント

任意。クエリで複数のドキュメントが選択された場合に、その操作で更新するドキュメントを決定します。db.collection.findAndModify() は、この引数で指定されたソート順で、最初のドキュメントを更新します。

ソート引数がドキュメントでない場合、操作はエラーになります。

MongoDB では、コレクション内のドキュメントを特定の順序で保存することはありません。重複する値を含むフィールドでソートする場合、それらの値を含むドキュメントは任意の順序で返されます。

一貫したソート順序が必要な場合は、一意の値を含むフィールドを少なくとも 1 つ含めてソートしてください。これを保証する最も簡単な方法は、_idフィールドをソートのクエリに含めることです。

詳細については、「ソートの整合性」を参照してください。

remove
ブール値
remove フィールドまたは update フィールドのいずれかを指定する必要があります。query フィールドで指定されたドキュメントを削除します。選択したドキュメントを削除するには、これを true に設定します。デフォルト値は false です。
update
ドキュメントまたは配列

remove フィールドまたは update フィールドのいずれかを指定する必要があります。選択したドキュメントの更新を実行します。

new
ブール値
任意。true の場合、元のドキュメントではなく更新されたドキュメントを返します。デフォルト値は false です。
fields
ドキュメント

任意。返すフィールドのサブセット。fieldsドキュメントでは、次のように1を含むフィールドの包含を指定しています: fields: { <field1>: 1, <field2>: 1, ... }

fields引数がドキュメントでない場合、操作はエラーになります。

プロジェクションの詳細については、「fieldsプロジェクション」を参照してください。

upsert
ブール値

任意。update フィールドと組み合わせて使用します。

true の場合、findAndModify() により次のいずれかが行われます。

  • query に一致するドキュメントがない場合は、新しいドキュメントを作成します。詳しくは、「アップサートの動作」を参照してください。

  • query に一致する 1 つのドキュメントをアップデートします。

複数のアップサートを回避するため、query フィールドにユニークインデックスが付けられていることを確認します。例については、「ユニークインデックスを使用したアップサート」を参照してください。

デフォルトは false で、一致するものが見つからなくても新しいドキュメントは挿入されません

bypassDocumentValidation
ブール値
任意。 操作中にdb.collection.findAndModify()がドキュメント検証をバイパスできるようにします。 これにより、検証要件を満たさないドキュメントを更新できるようになります。
writeConcern
ドキュメント

任意。書込み保証(write concern)を表現するドキュメント。デフォルトの書込み保証を使用する場合は省略します。

トランザクションで実行される場合、操作の書込み保証 (write concern)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。

maxTimeMS
non-negative integer

任意。

時間制限をミリ秒単位で指定します。maxTimeMS の値を指定しない場合、操作はタイムアウトしません。値を 0 にすると、デフォルトの無制限動作を明示的に指定します。

MongoDB は、db.killOp() と同じメカニズムを使用して、割り当てられた時間制限を超えた操作を終了します。MongoDB は、指定された割り込みポイントのいずれかでのみ操作を終了します。

collation
ドキュメント

任意。

操作に使用する照合を指定します。

照合を指定すると、大文字・小文字やアクセント記号など、文字列を比較するための言語独自のルールを指定できます。

照合オプションの構文は次のとおりです。

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

照合を指定する場合、locale フィールドは必須ですが、その他の照合フィールドはすべて任意です。フィールドの説明については、照合ドキュメントを参照してください。

照合が指定されていなくても、コレクションにデフォルトの照合が設定されている場合(db.createCollection() を参照)には、コレクションの照合が使用されます。

コレクションにも操作にも照合が指定されていない場合、MongoDB では以前のバージョンで使用されていた単純なバイナリ比較によって文字列が比較されます。

1 つの操作に複数の照合は指定できません。たとえば、フィールドごとに異なる照合を指定できません。また、ソートと検索を一度に実行する場合、検索とソートで別の照合を使用できません。

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 は、集計パイプラインが使用される更新では使用できません。

ドキュメント

任意。

変数のリストを含むドキュメントを指定します。これにより、変数をクエリテキストから分離することで、コマンドの読みやすさを向上させることができます。

ドキュメントの構文は次のとおりです。

{
<variable_name_1>: <expression_1>,
...,
<variable_name_n>: <expression_n>
}

変数は式によって返された値に設定され、その後は変更できません。

コマンド内の変数の値にアクセスするには、二重ドル記号の接頭辞($$)を $$<variable_name> 形式にした変数名とともに使用します。たとえば次のとおりです。$$targetTotal

結果のフィルタリングに変数を使用するには、$expr 演算子内の変数にアクセスする必要があります。

let と変数を使用した完全な例については、「let における変数の使用」を参照してください。

バージョン 5.0 で追加

削除操作では、クエリがドキュメントと一致する場合、 findAndModify() は削除されたドキュメントを返します。クエリが削除するドキュメントと一致しない場合、 findAndModify() nullを返します。

更新操作の場合、 findAndModify()次のいずれかを返します。

  • new パラメーターがセットされていないか、false の場合

    • クエリがドキュメントにマッチした場合、変更前のドキュメント。

    • それ以外の場合は、null

  • newtrueの場合

    • クエリが一致を返した場合、更新されたドキュメント。

    • upsert: trueでクエリに一致するドキュメントがない場合、挿入されたドキュメント。

    • それ以外の場合は、null

重要

言語の整合性

find()findAndModify() のプロジェクションを集計の $projectステージと一貫性を持たせるために、

fieldsオプションは次のような形式のドキュメントを取ります:

{ field1: <value>, field2: <value> ... }
プロジェクション
説明
<field>: <1 or true>
フィールドを包含することを指定します。プロジェクションの値としてゼロ以外の整数を指定した場合、その値を true として処理します。
<field>: <0 or false>
フィールドの除外を指定します。
"<field>.$": <1 or true>

$ 配列プロジェクション 演算子を使用して、配列フィールドのクエリ条件に一致する最初の要素を返します。プロジェクションの値としてゼロ以外の整数を指定した場合、その値を true として処理します。

ビューには使用できません。

<field>: <array projection>

配列プロジェクション 演算子($elemMatch$slice)を使用して、含める配列要素を指定します。

ビューには使用できません。

<field>: <aggregation expression>

プロジェクションを行ったフィールドの値を指定します。

集計式と構文の使用(リテラルと集計変数の使用を含む)では、新しいフィールドをプロジェクションしたり、既存のフィールドを新しい値でプロジェクションしたりできます。

  • プロジェクションの値として数値でもブール値でもないリテラル(例えば、文字列リテラルや配列、演算子式)を指定すると、フィールドは新しい値でプロジェクションされます。次に例を示します。

    • { field: [ 1, 2, 3, "$someExistingField" ] }

    • { field: "New String Value" }

    • { field: { status: "Active", total: { $sum: "$existingArray" } } }

  • フィールドにリテラル値をプロジェクションするには、$literal 集計式を使用します。次に例を示します。

    • { field: { $literal: 5 } }

    • { field: { $literal: true } }

    • { field: { $literal: { fieldWithValue0: 0, fieldWithValue1: 1 } } }

埋め込みドキュメント内のフィールドの場合は、次のいずれかを使用してフィールドを指定できます。

  • ドット表記の場合は次のようになります。 "field.nestedfield": <value>

  • ネストされた形式の例 { field: { nestedfield: <value> } }

_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 ではない、または multifalse

    • アップデートの一致条件は、次のいずれかです。

      • 単一の等価述語。例: { "fieldA" : "valueA" }

      • 等価述語の論理 AND。例: { "fieldA" : "valueA", "fieldB" : "valueB" }

    • 等価述語内のフィールドが、一意なインデックス キー パターン内のフィールドと一致。

    • 更新操作が、一意なインデックス キー パターン内のフィールドを変更しない。

次の表に示す upsert 操作の例では、キーの衝突が発生した場合に更新されるか失敗します。

ユニークインデックスキーのパターン
アップデート操作
結果
{ name : 1 }
db.people.updateOne(
{ name: "Andy" },
{ $inc: { score: 1 } },
{ upsert: true }
)
マッチしたドキュメントの score フィールドが 1 インクリメントされます。
{ name : 1 }
db.people.updateOne(
{ name: { $ne: "Joe" } },
{ $set: { name: "Andy" } },
{ upsert: true }
)
一意なインデックス キー パターン(name)のフィールドが変更されるため、操作は失敗します。
{ name : 1 }
db.people.updateOne(
{ name: "Andy", email: "andy@xyz.com" },
{ $set: { active: false } },
{ upsert: true }
)
等式述語フィールド(nameemail)がインデックス キー フィールド(name)と一致しないため、操作は失敗します。

シャーディングされたコレクションでfindAndModifyを使用するには、

  • 1つのシャードのみをターゲットにする場合は、query フィールドで部分的なシャードキーを使用できます。または

  • query フィールドの完全なシャードキーに等価条件を指定できます。

シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。シャードキーがないドキュメントをターゲットにするには、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オプションのサポートを追加します。これにより、検証ルールを使用してコレクションにドキュメントを挿入または更新するときにドキュメント検証をバイパスできます。

ドキュメントを更新する場合の 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)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。

db.collection.findAndModify()操作によってドキュメントが正常に検出され、変更された場合、その操作によってoplog(操作ログ)にエントリが追加されます。操作が失敗した場合、または更新するドキュメントが見つからなかった場合は、その操作によって oplog にエントリーが追加されることはありません。

次のメソッドは、クエリの条件に一致するドキュメントの people コレクション内の既存のドキュメントを更新して返します。

db.people.findAndModify({
query: { name: "Tom", state: "active", rating: { $gt: 10 } },
sort: { rating: 1 },
update: { $inc: { score: 1 } }
})

このメソッドは、次のアクションを実行します。

  1. query は、name フィールドの値が Tomstate フィールドの値が activerating フィールドの値が greater than 10 であるドキュメントを people コレクション内で検索します。

  2. sort は、クエリの結果を昇順に並べます。複数のドキュメントが query 条件を満たす場合、メソッドはこの sort の順序に従って最初のドキュメントを変更対象として選択します。

  3. incrementsにより、scoreフィールドの値が 1 だけ更新されます。

  4. このメソッドは元の(つまり 変更前の)このアップデート用に選択されたドキュメントを返します。

    {
    "_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 は、集計パイプラインが使用される更新では使用できません。

次のドキュメントを使用してコレクション 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() は、更新の集計パイプラインを受け入れることができます。このパイプラインには次のステージが含まれる可能性があります。

集計パイプラインを使用すると、現在のフィールド値に基づいて条件付きのアップデートを表現したり、あるフィールドを他のフィールドの値を使用してアップデートするなど、より表現内容の多いアップデート ステートメントが可能になります。

たとえば、次のドキュメントを含むコレクション 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
} )

注意

パイプラインで使用される $set は、更新演算子 $set ではなく、集計ステージ $set を参照します

この操作は更新されたドキュメントを返します。

{
"_id" : 1,
"grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ],
"total" : 250
}

バージョン 5.0 で追加

コマンド内の他の場所からアクセスできる変数を定義するには let オプションを使用します。

注意

変数を使用して結果をフィルタリングするには、$expr 演算子内の変数にアクセスする必要があります。

コレクション cakeFlavors を以下ように作成します。

db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )

次の例では、lettargetFlavor 変数を定義し、その変数を使用してケーキのフレーバーをチェリーからオレンジに変更します。

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 ロールの使用

ロール、ユーザー、コレクションを作成するには、次の手順を実行します。

1

必要な権限とリソースを持つ 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: [ ] } )
2

必要なロールを持つ James および Michelle という名前のユーザーを作成します。

db.createUser( {
user: "James",
pwd: "js008",
roles: [
{ role: "Billing", db: "test" }
]
} )
db.createUser( {
user: "Michelle",
pwd: "me009",
roles: [
{ role: "Provider", db: "test" }
]
} )
3

実行:

db.medical.insertMany( [
{
_id: 0,
patientName: "Jack Jones",
diagnosisCode: "CAS 17",
creditCard: "1234-5678-9012-3456"
},
{
_id: 1,
patientName: "Mary Smith",
diagnosisCode: "ACH 01",
creditCard: "6541-7534-9637-3456"
}
] )

Provider ロールを持つ Michelle としてログインし、更新を実行します。

1

実行:

db.auth( "Michelle", "me009" )
2

実行:

// 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 のユーザー ロールの共通部分が空ではないドキュメントを返します。MichelleProvider のロールを持つので、更新が実行されます。

次に、Provider ロールを持たない James としてログインし、同じ更新の実行を試みます。

1

実行:

db.auth( "James", "js008" )
2

実行:

// 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"
}
} )

前の例では、ドキュメントは更新されません。

戻る

db.collection.find