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

db.collection.findOneAndUpdate()

項目一覧

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

MongoDB とドライバー

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

C#Java SyncNode.jsPyMongoCC++GoJava RSKotlin CoroutineKotlin SyncPHPMongoidRustScala
db.collection.findOneAndUpdate( filter, update, options )

filterおよびsort条件に基づいて単一のドキュメントを更新します。

Tip

バージョン 8.0 の新機能 :updateOne() メソッドには、ユーザーが指定したソート順で最初のドキュメントを更新する sort オプションが含まれています。

次の値を返します。デフォルトでは元のドキュメントを返します。returnNewDocumenttrue に設定されているか returnDocumentafter に設定されている場合、更新されたドキュメントを返します。

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

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

  • 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
タイプ
説明
filter
ドキュメント

更新の選択基準。find()メソッドと同じクエリ セレクターを使用できます。

コレクションで返される最初のドキュメントを更新するには、空のドキュメント{ }を指定します。

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

クエリ フィールドがドキュメントでない場合、操作はエラーを返します。

filterに一致するドキュメントがない場合、ドキュメントは更新されません。

update
ドキュメントまたは配列

更新ドキュメントまたは集計パイプライン

writeConcern
ドキュメント

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

{ w: <value>, j: <boolean>, wtimeout: <number> }

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

projection
ドキュメント

任意。返すフィールドのサブセット。

返されたドキュメント内のすべてのフィールドを返すには、このパラメーターを省略します。

プロジェクションの引数がドキュメントでない場合、操作はエラーになります。

sort
ドキュメント

任意。 filterに一致するドキュメントの並べ替え順序を指定します。

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

cursor.sort() を参照してください。

maxTimeMS
数値
任意。 操作が 以内に完了する必要がある制限時間をミリ秒単位で指定します。 制限を超えた場合はエラーがスローされます。
upsert
ブール値

任意。true の場合、findOneAndUpdate() によって次のいずれかが実行されます。

  • filter に一致するドキュメントがない場合は、新しいドキュメントを作成します。詳細については、アップサートの動作を参照してください。returnNewDocumenttrueでない限り、新しいドキュメントを挿入した後にnullを返します。

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

複数のアップサートを回避するため、filterフィールドが一意にインデックスされていることを確認します。

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

returnDocument
string

任意。mongosh 0.13.2 以降、returnDocumentreturnNewDocumentの代替となります。両方のオプションが設定されている場合は、returnDocument が優先されます。

returnDocument: "before" は元のドキュメントを返します。 returnDocument: "after"は更新されたドキュメントを返します。

returnNewDocument
ブール値

任意。trueの場合、元のドキュメントではなく更新されたドキュメントを返します。

デフォルトは false です。

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

再試行可能な書き込みでは、更新を実行する前に、findOneAndUpdate() メソッドを使用してドキュメント全体をレプリカセット内の各ノードの特別なサイドコレクションにコピーする必要があります。そのため、大きな文書や大きなレプリカセットを扱う場合、findOneAndUpdate() はコストが大きい操作になる可能性があります。

バージョン 8.0 の新機能 :ユーザー定義の順序付けで最初のドキュメントをより優れたパフォーマンスで更新するため、sort オプションを指定した db.collection.updateOne() メソッドを使用します。

db.collection.findOneAndUpdate() は、 filter に一致するコレクション内の最初に一致するドキュメントを更新します。filter に一致するドキュメントがない場合、ドキュメントは更新されません。

sortパラメータを使用して、どのドキュメントを更新するかを制御することができます。

重要

言語の整合性

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

projectionパラメータは次の形式のドキュメントを取ります。

{ 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 フィールドが含まれます。

プロジェクションの詳細については、以下も参照してください。

シャーディングされたコレクションで db.collection.findOneAndUpdate() を使用するには、クエリフィルターにシャード キーの等価条件が含まれている必要があります。

シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合があります。シャードキーがないドキュメントをターゲットにするには、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)を明示的に設定しないでください。トランザクションで書込み保証を使用するには、「トランザクション書込み保証」を参照してください。

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 }

次の操作では、プロジェクションを使用して、返されたドキュメントの _idpointsassignment フィールドのみを表示します。

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

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

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

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

注意

パイプラインで使用される $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
}

戻る

db.collection.findOneAndReplace