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

findAndModify

項目一覧

  • 定義
  • 互換性
  • 構文
  • コマンドフィールド
  • 出力
  • 動作
findAndModify

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

Tip

mongoshでは、このコマンドは db.collection.findAndModify()ヘルパー メソッドを通じて実行することもできます。

ヘルパー メソッドはmongoshユーザーには便利ですが、データベースコマンドと同じレベルの情報は返されない可能性があります。 便宜上必要ない場合、または追加の戻りフィールドが必要な場合は、 データベースコマンドを使用します。

このコマンドは、次の環境でホストされている配置で使用できます。

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

注意

このコマンドは、すべての MongoDB Atlas クラスターでサポートされています。すべてのコマンドに対する Atlas のサポートについては、 「サポートされていないコマンド」を参照してください。

  • MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン

  • MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン

バージョン 5.0 での変更

このコマンドの構文は、次のとおりです。

db.runCommand(
{
findAndModify: <collection-name>,
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: <array>,
hint: <document|string>,
comment: <any>,
let: <document> // Added in MongoDB 5.0
}
)

このコマンドは、次のフィールドを使用します。

フィールド
タイプ
説明
query
ドキュメント

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

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

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

sort

ドキュメント

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

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

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

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

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

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

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

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

任意。返すフィールドのサブセット。fields ドキュメントでは、fields: { <field1>: 1, <field2>: 1, ... } のように 1 を含むフィールドを含めることを指定しています。「プロジェクション」を参照してください。

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

upsert
ブール値

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

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

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

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

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

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

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

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

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

maxTimeMS
non-negative integer

任意。

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

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

findAndModify
string
コマンドを実行するコレクション。
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 は、集計パイプラインが使用される更新では使用できません。

hint
ドキュメントまたは文字列

任意。query をサポートするために使用するインデックスを指定するドキュメントまたは文字列です。

このオプションには、インデックス仕様ドキュメントまたはインデックス名の文字列を指定できます。

存在しないインデックスを指定した場合、操作はエラーになります。

例については、「findAndModify 操作での hint の指定」を参照してください。

comment
any

任意。このコマンドに添付するユーザー指定のコメント。設定すると、このコメントは以下の場所にこのコマンドの記録と合わせて表示されます。

コメントには、有効な BSON 型(string, integer, object, array など)を使用できます。

ドキュメント

任意。

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

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

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

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

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

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

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

バージョン 5.0 で追加

findAndModify コマンドは、次のフィールドを含むドキュメントを返します。

フィールド
タイプ
説明
value
ドキュメント
コマンドの戻り値が含まれます。詳しくは、value を参照してください。
lastErrorObject
ドキュメント
更新されたドキュメントに関する情報が含まれます。詳しくは、lastErrorObject を参照してください。
ok
数値
コマンドの実行状態が入ります。成功した場合は 1、エラーが発生した場合は 0 になります。

lastErrorObject 埋め込みドキュメントには、次のフィールドが含まれています。

フィールド
タイプ
説明
n
integer
更新述語に一致したドキュメントの数、またはコマンドによって挿入または削除されたドキュメントの数が含まれます。
updatedExisting
ブール値

update 操作が次の結果の場合、true が入ります。

  • 既存のドキュメントを更新しました。

  • ドキュメントは見つかりましたが、すでに目的の状態になっていたため、実際には更新は行われませんでした。

upserted
ドキュメント
upsert: trueを使用した update 操作によって新しいドキュメントが生成された場合、挿入されたドキュメントの ObjectId が入ります。

remove 操作では、クエリがドキュメントと一致する場合、value には削除されたドキュメントが入ります。クエリが削除するドキュメントと一致しない場合、value には null が入ります。

update 操作の場合、value 埋め込みドキュメントには次の内容が含まれます。

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

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

    • それ以外の場合は、null

  • newtrueの場合

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

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

    • それ以外の場合は、null

重複を防ぐためのユニークインデックスがない限り、アップサートによって重複したドキュメントが作成されることがあります。

Andy という名前のドキュメントが存在せず、複数のクライアントがほぼ同時に次のコマンドを発行する例を考えます。

db.runCommand(
{
findAndModify: "people",
query: { name: "Andy" },
update: { $inc: { score: 1 } },
upsert: true
}
)

いずれかのクライアントがデータを正常に挿入する前にすべての findAndModify 操作がクエリ フェーズを終了し、かつ name フィールドにユニークインデックスがない場合、各 findAndModify 操作によって挿入が行われて、name: Andyを含む複数のドキュメントが作成される可能性があります。

name フィールドに一意なインデックスを設定すると、ドキュメントが 1 つだけ作成されるようになります。一意なインデックスが設定されると、複数の findAndModify 操作で次の動作が見られるようになります。

  • 正確に 1 つの findAndModify 操作で新しいドキュメントが正常に挿入されます。

  • その他の findAndModify 操作は、新しく挿入されたドキュメントを更新するか、一意なキーの競合が原因で失敗します。

    他の findAndModify 操作で新しく挿入されたドキュメントを更新するには、次の条件がすべて満たされている必要があります。

    • ターゲット コレクションに一意なインデックスがあるため、重複キー エラーが発生。

    • 更新操作が 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 フィールドの完全なシャードキーに等価条件を指定できます。

  • バージョン7.1以降では、クエリ仕様でシャードキーまたは_idフィールドを指定する必要がありません。

シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。シャードキーがないドキュメントをターゲットにするには、null 等価一致を別のフィルター条件(_id フィールドなど)と組み合わせて使用できます。以下に例を挙げます。

{ _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key

シャードキー フィールドが不変の _id フィールドでない限り、ドキュメントのシャードキー値を更新できます。

警告

シャーディングされたコレクション内のドキュメントには、シャード キー フィールドがないことがあります。ドキュメントのシャード キーの値を変更するときに、誤ってシャード キーを削除しないように注意してください。

既存のシャードキー値をfindAndModifyで更新する方法:

  • 必ず mongos 上で使用します。シャードに直接操作を実行しないでください

  • トランザクション内で、または 再試行可能な書き込みとして実行する必要があります

  • 完全なシャードキーに等価フィルターを含める必要があります

シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合がありますfindAndModify を使用してドキュメントにないシャードキーを設定するには、以下が必要です。

  • 必ず mongos 上で使用します。シャードに直接操作を実行しないでください

  • 新しいシャードキー値が null でない場合は、トランザクション内で実行するか、再試行可能な書き込みとして実行する必要があります

  • 完全なシャードキーに等価フィルターを含める必要があります

Tip

欠落しているキー値は NULL 等価一致の一部として返されるため、NULL 値のキーが更新されないように、必要に応じて追加のクエリ条件(_id フィールドなど)を追加します。

以下も参照してください。

findAndModifyコマンドはbypassDocumentValidationオプションのサポートを追加します。これにより、検証ルールを使用してコレクションにドキュメントを挿入または更新するときにドキュメント検証をバイパスできます。

ドキュメントを更新する場合の findAndModify メソッドと updateOne() メソッドの動作は異なります。

  • 更新条件に一致するドキュメントが複数ある場合、findAndModify では、sort を指定することで、更新するドキュメントの選択に関して一定の制御が可能です。

    updateOne() は一致する最初のドキュメントを更新します。

  • デフォルトでは、findAndModify で、変更前のドキュメントと操作のステータスが含まれたオブジェクトが返されます。更新済みのドキュメントを取得するには、new オプションを使用します。

    updateOne() メソッドは、操作のステータスを含む WriteResult() オブジェクトを返します。

    更新されたドキュメントを返すには、find() メソッドを使用します。ただし、更新してからドキュメントを取得するまでの間に、他の更新によってドキュメントが変更される可能性があります。また、更新によって 1 つのドキュメントのみが変更されたが、複数のドキュメントが一致した場合は、更新されたドキュメントを識別するために追加のロジックを使用する必要があります。

1 つのドキュメントを変更する場合、findAndModify メソッドと updateOne() メソッドの両方でドキュメントがアトミックに更新されます。これらのメソッドの相互作用と操作順序の詳細については、「アトミック性とトランザクション」を参照してください。

Tip

以下も参照してください。

findAndModify分散トランザクション内で使用できます。

重要

ほとんどの場合、分散トランザクションでは 1 つのドキュメントの書き込み (write) よりもパフォーマンス コストが高くなります。分散トランザクションの可用性は、効果的なスキーマ設計の代わりにはなりません。多くのシナリオにおいて、非正規化されたデータモデル(埋め込みドキュメントと配列)が引き続きデータやユースケースに最適です。つまり、多くのシナリオにおいて、データを適切にモデリングすることで、分散トランザクションの必要性を最小限に抑えることができます。

トランザクションの使用に関するその他の考慮事項(ランタイム制限や oplog サイズ制限など)については、「本番環境での考慮事項」も参照してください。

トランザクションがクロスシャード間書き込みトランザクション(write transaction)でない場合に、分散トランザクション内にコレクションとインデックスを作成できます。

findAndModifyupsert: trueは、既存のコレクションまたは存在しないコレクションで実行できます。存在しないコレクションに対して実行すると、操作によってコレクションが作成されます。

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

次のコマンドは、people コレクション内の既存のドキュメントで、ドキュメントが query 条件に一致するものを更新します。

db.runCommand(
{
findAndModify: "people",
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. updatescore フィールドの値を 1 ずつ increments します。

  4. このコマンドは、次のフィールドを含むドキュメントを返します。

    • コマンドの詳細を含むlastErrorObjectフィールド( trueであるフィールドupdatedExistingを含む)と

    • この更新で選択された元の(つまり、変更前の)ドキュメントを含む value 値フィールド

      {
      "lastErrorObject" : {
      "connectionId" : 1,
      "updatedExisting" : true,
      "n" : 1,
      "syncMillis" : 0,
      "writtenTo" : null,
      "err" : null,
      "ok" : 1
      },
      value" : {
      "_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
      "name" : "Tom",
      "state" : "active",
      "rating" : 100,
      "score" : 5
      },
      "ok" : 1
      }

更新されたドキュメントを value フィールドに返すには、コマンドに new:true オプションを追加します。

query 条件に一致するドキュメントがない場合、コマンドは value フィールドに null を含むドキュメントを返します。

{ "value" : null, "ok" : 1 }

mongosh および多くのドライバーでは findAndModify() ヘルパー メソッドを提供します。シェルヘルパーを使用すると、前述の操作は次の形式になります。

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

ただし、findAndModify() シェルヘルパー メソッドは変更されていないドキュメントのみを返します。または、newtrue の場合には、更新されたドキュメントを返します。

{
"_id" : ObjectId("54f62d2885e4be1f982b9c9c"),
"name" : "Tom",
"state" : "active",
"rating" : 100,
"score" : 5
}

次の findAndModify コマンドには、update 操作の upsert: true オプションが含まれおり、一致するドキュメントをアップデートするか、一致するドキュメントが存在しない場合は新しいドキュメントを作成します。

db.runCommand(
{
findAndModify: "people",
query: { name: "Gus", state: "active", rating: 100 },
sort: { rating: 1 },
update: { $inc: { score: 1 } },
upsert: true
}
)

コマンドが一致するドキュメントを見つけた場合、コマンドは更新を実行します。

一致するドキュメントが見つからない場合、upsert: trueupdate 操作によって挿入が行われ、次のフィールドを含むドキュメントが返されます。

  • コマンドの詳細を含む lastErrorObject フィールド(新しく挿入されたドキュメントの _id 値を含むフィールド upserted など)と

  • null を含む value フィールド。

{
"value" : null,
"lastErrorObject" : {
"updatedExisting" : false,
"n" : 1,
"upserted" : ObjectId("54f62c8bc85d4472eadea26f")
},
"ok" : 1
}

次の findAndModify コマンドには、upsert: true オプションと new:true オプションが両方含まれています。このコマンドでは、一致するドキュメントを更新して更新後のドキュメントを返すか、一致するドキュメントが存在しない場合はドキュメントを挿入して、挿入された新しいドキュメントを value フィールドで返します。

次の例では、people コレクション内のどのドキュメントも query 条件に一致しません。

db.runCommand(
{
findAndModify: "people",
query: { name: "Pascal", state: "active", rating: 25 },
sort: { rating: 1 },
update: { $inc: { score: 1 } },
upsert: true,
new: true
}
)

このコマンドは、value フィールドに新しく挿入されたドキュメントを返します。

{
"lastErrorObject" : {
"connectionId" : 1,
"updatedExisting" : false,
"upserted" : ObjectId("54f62bbfc85d4472eadea26d"),
"n" : 1,
"syncMillis" : 0,
"writtenTo" : null,
"err" : null,
"ok" : 1
},
"value" : {
"_id" : ObjectId("54f62bbfc85d4472eadea26d"),
"name" : "Pascal",
"rating" : 25,
"state" : "active",
"score" : 1
},
"ok" : 1
}

次の例では、rating フィールドに sort 仕様を含めることで、state の値が active であり、一致するドキュメントの中で最も rating が低い 1 つのドキュメントを people コレクションから削除します。

db.runCommand(
{
findAndModify: "people",
query: { state: "active" },
sort: { rating: 1 },
remove: true
}
)

このコマンドは、次のように、削除されたドキュメントを返します。

{
"lastErrorObject" : {
"connectionId" : 1,
"n" : 1,
"syncMillis" : 0,
"writtenTo" : null,
"err" : null,
"ok" : 1
},
"value" : {
"_id" : ObjectId("54f62a6785e4be1f982b9c9b"),
"name" : "XYZ123",
"score" : 1,
"state" : "active",
"rating" : 3
},
"ok" : 1
}

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

コレクション myCollは、次のドキュメントを含みます。

{ _id: 1, category: "café", status: "A" }
{ _id: 2, category: "cafe", status: "a" }
{ _id: 3, category: "cafE", status: "a" }

次の操作には照合オプションが含まれます。

db.runCommand(
{
findAndModify: "myColl",
query: { category: "cafe", status: "a" },
sort: { category: 1 },
update: { $set: { status: "Updated" } },
collation: { locale: "fr", strength: 1 }
}
)

この操作を実行すると次のドキュメントが返されます。

{
"lastErrorObject" : {
"updatedExisting" : true,
"n" : 1
},
"value" : {
"_id" : 1,
"category" : "café",
"status" : "A"
},
"ok" : 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.runCommand(
{
findAndModify: "students",
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.runCommand(
{
findAndModify: "students2",
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 }
]
}

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.runCommand(
{
findAndModify: "students2",
query: { "_id" : 1 },
update: [ { $set: { "total" : { $sum: "$grades.grade" } } } ],
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
}
{
"_id" : 2,
"grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85,"std" : 4 } ]
}

mongosh で、次のドキュメントを含む members コレクションを作成します。

db.members.insertMany( [
{ "_id" : 1, "member" : "abc123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" },
{ "_id" : 3, "member" : "lmn123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 4, "member" : "pqr123", "status" : "D", "points" : 20, "misc1" : "Deactivated", "misc2" : null },
{ "_id" : 5, "member" : "ijk123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 6, "member" : "cde123", "status" : "A", "points" : 86, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }
] )

コレクションに次のインデックスを作成します。

db.members.createIndex( { status: 1 } )
db.members.createIndex( { points: 1 } )

次の操作は、インデックス { status: 1 } を使用することを明示的に示しています。

db.runCommand({
findAndModify: "members",
query: { "points": { $lte: 20 }, "status": "P" },
remove: true,
hint: { status: 1 }
})

注意

存在しないインデックスを指定した場合、操作はエラーになります。

使用されたインデックスを確認するには、次の操作で explain を実行します。

db.runCommand(
{
explain: {
findAndModify: "members",
query: { "points": { $lte: 20 }, "status": "P" },
remove: true,
hint: { status: 1 }
},
verbosity: "queryPlanner"
}
)

バージョン 5.0 で追加

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

注意

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

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

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

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

db.cakeFlavors.runCommand( {
findAndModify: db.cakeFlavors.getName(),
query: { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } },
update: { flavor: "orange" },
let: { targetFlavor: "cherry" }
} )

戻る

find