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

db.collection.update()

項目一覧

  • 定義
  • 互換性
  • 構文
  • アクセス制御
  • 動作
  • WriteResult

重要

非推奨の mongosh メソッド

このメソッドは mongoshでは非推奨です。 別のメソッドについては、「レガシーmongo shellとの互換性の変更 」を参照してください。

db.collection.update(query, update, options)

既存のドキュメント、またはコレクション内のドキュメントを変更します。このメソッドは、update パラメータに応じて、既存のドキュメントの特定のフィールドを変更したり、既存のドキュメント全体を置き換えたりすることができます。

デフォルトでは、db.collection.update() メソッドは 単一のドキュメントを更新します。クエリ条件に一致するすべてのドキュメントを更新するには、オプション multi: true を含めます。

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

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

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

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

Atlas UI を使用して MongoDB Atlas でホストされているドキュメントを更新する方法については、 「 1 つのドキュメントの編集 」を参照してください。

バージョン 5.0 での変更

db.collection.update() メソッドの形式は次のとおりです。

db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string>,
let: <document> // Added in MongoDB 5.0
}
)

db.collection.update() メソッドは次のパラメーターを取ります。

Parameter
タイプ
説明
ドキュメント

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

upsert: true を指定してupdate() を実行して、クエリが既存のドキュメントと一致しない場合、クエリがドット表記を使用して _id フィールドに条件を指定すると、MongoDB は新しいドキュメントの挿入を拒否します。

ドキュメントまたはパイプライン

適用される変更内容。次のいずれかになります。

更新演算子式のみが含まれます。

<field1>: <value1> ペアのみが含まれています。

次の集計ステージのみが含まれます。

詳細と例については、「Oplog エントリ」を参照してください。

ブール値

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

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

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

upsertmulti の両方が true であり、クエリに一致するドキュメントがない場合、アップデート操作によって 1 つのドキュメントのみが挿入されます。

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

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

ブール値

任意。 trueに設定すると、 はquery条件を満たす複数のドキュメントを更新します。 falseに設定すると、 は 1 つのドキュメントを更新します。 デフォルト値はfalseです。 詳細については、「複数のドキュメントの更新例 」を参照してください。

ドキュメント

任意。書込み保証 (write concern) を表現するドキュメント。省略すると、デフォルトの書込み保証 (write concern) w: "majority" が使用されます。

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

writeConcern の使用例については、「デフォルトの書込み保証 (write concern) の上書き」を参照してください。

ドキュメント

任意。

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

collation の使用例については、「「照合の指定」を参照してください。

配列

任意。配列フィールドの更新操作でどの配列要素を変更するかを決定するフィルター ドキュメントの配列。

アップデート ドキュメントでは、 $[<identifier>]を使用して、 arrayFilters内の対応するフィルター ドキュメントと一致する配列要素のみをアップデートするための識別子を定義します。

識別子が更新ドキュメントに含まれていない場合、識別子の配列フィルター ドキュメントを作成することはできません。

例については、「配列アップデート操作にarrayFiltersを指定する」を参照してください。

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

任意。 クエリ述語 をサポートするために使用する インデックス を指定するドキュメントまたは string です。

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

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

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

ドキュメント

任意。

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

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

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

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

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

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

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

バージョン 5.0 で追加

このメソッドは、操作のステータスを含む WriteResult ドキュメントを返します。

authorizationを使用して実行されている配置では、ユーザーには次の特権を含むアクセス権が必要です。

  • update 指定したコレクションに対するアクション。

  • find 指定したコレクションに対するアクション。

  • insert 操作の結果がアップサートになる場合、指定されたコレクションに対して実行されるアクション。

組み込みロール readWrite は必要な特権を提供します。

$expr 演算子を使用して upsert フラグを true に設定しようとすると、エラーが発生します。

シャーディングされたコレクションで db.collection.update()multi: false と一緒に使用するには、_id フィールドに完全一致を含めるか、単一のシャードをターゲットにする(シャードキーを含めるなど)必要があります。

db.collection.update() が更新操作(ドキュメント置換操作ではない)を実行する場合、db.collection.update() では複数のシャードをターゲットにすることができます。

Tip

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

ドキュメント置き換え操作では、まずクエリフィルターを使用して 1 つのシャードに対象を絞り込もうとします。クエリフィルターで 1 つのシャードに絞り込めない場合は、置き換えドキュメントで絞り込もうとします。

以前のバージョンでは、この操作では置換ドキュメントを使用するターゲットを試行します。

upsert: true を含み、かつシャーディングされたコレクションにある db.collection.update() の操作には、filter に完全なシャードキーを含める必要があります。

  • 更新操作に使用します。

  • ドキュメントの置き換え操作用。

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

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

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

既存のシャードキー値をdb.collection.update()で変更するには

Tip

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

シャーディングされたコレクションの upsert」も参照してください。

シャーディングされたコレクション内のドキュメントには、シャードキー フィールドがない場合がありますdb.collection.update()を使用してドキュメントの欠落しているシャードキーを設定するには、mongosで実行する必要があります。シャードに対して直接操作を実行しないでください

さらに、次の要件も適用されます。

タスク
要件
設定するには null
  • multi: true を指定できます。

  • upsert: trueの場合は、シャード キー全体に等価フィルターが必要です。

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

  • 必ずmulti: falseを指定します。

  • 次のいずれかの場合、完全なシャードキーに等価フィルターが必要です。

    • upsert: trueまたは、

    • 置換ドキュメントを使用しており、新しいシャードキー値が別のシャードに属している場合。

Tip

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

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

db.collection.update()分散トランザクション内で使用できます。

重要

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

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

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

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

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

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

以下のタブでは、一般的な update() 操作のさまざまな例を紹介しています。

mongosh では、次のドキュメントを含む books コレクションが作成されます。このコマンドは、まず、以前に存在していたすべてのドキュメントを books コレクションから排除します。

db.books.remove({});
db.books.insertMany([
{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : { "publisher" : "1111", "pages" : 430 },
"tags" : [ "technology", "computer" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
},
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : { "publisher" : "5555", "pages" : 150 },
"tags" : [ ],
"ratings" : [ { "by" : "xyz", "rating" : 5 } ],
"reorder" : false
}
]);

<update> ドキュメントに、$set 修飾子を使用するような、更新演算子 が含まれている場合は、次のようになります。

  • <update> ドキュメントには、更新演算子のみを含める必要があります。

  • db.collection.update() メソッドは、ドキュメント内の対応するフィールドのみを更新します。

    • 埋め込みドキュメントまたは配列全体を更新するには、フィールドの置換値を指定します。

    • 埋め込みドキュメントまたは配列内の特定のフィールドを更新するには、ドット表記を使用してフィールドを指定します。

db.books.update(
{ _id: 1 },
{
$inc: { stock: 5 },
$set: {
item: "ABC123",
"info.publisher": "2222",
tags: [ "software" ],
"ratings.1": { by: "xyz", rating: 3 }
}
}
)

この操作において:

  • <query>{ _id: 1 } パラメーターは、更新するドキュメントを指定します。

  • $inc 演算子は、stock フィールドを増分し、

  • $set 演算子は、次の値を置き換えます:

    • item フィールド、

    • publisher info埋め込みドキュメント内のフィールド、

    • tags フィールド、

    • ratings 配列の 2 番目の要素。

更新されたドキュメントは次のとおりです:

{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : { "publisher" : "2222", "pages" : 430 },
"tags" : [ "software" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : false
}

この操作は、次の SQL ステートメントに対応しています。

UPDATE books
SET stock = stock + 5
item = "ABC123"
publisher = 2222
pages = 430
tags = "software"
rating_authors = "ijk,xyz"
rating_values = "4,3"
WHERE _id = 1

query パラメータが複数のドキュメントと一致した場合、この操作では一致するドキュメントが 1 つだけ更新されます。複数のドキュメントを更新するには、multi オプションを true に設定します。

Tip

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

次の操作では、$push 更新演算子を使用して、新しいオブジェクトを ratings 配列に追加します。

db.books.update(
{ _id: 2 },
{
$push: { ratings: { "by" : "jkl", "rating" : 2 } }
}
)

更新されたドキュメントは次のとおりです:

{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : {
"publisher" : "5555",
"pages" : 150
},
"tags" : [ ],
"ratings" : [
{ "by" : "xyz", "rating" : 5 },
{ "by" : "jkl", "rating" : 2 }
],
"reorder" : false
}

Tip

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

次の操作では、 $unset演算子を使用して、 { _id: 1 }を持つドキュメントからtagsフィールドを削除します。

db.books.update( { _id: 1 }, { $unset: { tags: 1 } } )

更新されたドキュメントは次のとおりです:

{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : {
"publisher" : "1111",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
}

$unsetに相当する直接 SQL はありませんが、 $unsetは次の SQL コマンドに類似しており、 booksテーブルからtagsフィールドを削除します。

ALTER TABLE books
DROP COLUMN tags

Tip

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

multitrue に設定されている場合、db.collection.update() メソッドは <query> 条件を満たすすべてのドキュメントを更新します。multi 更新操作は他の読み取り/書き込み操作とインターリーブする可能性があります。

次の操作は、stock10 以下であるすべてのドキュメントの reorder フィールドを true に設定します。reorder フィールドが一致するドキュメントに存在しない場合、$set 演算子は指定された値を持つフィールドを追加します。

db.books.update(
{ stock: { $lte: 10 } },
{ $set: { reorder: true } },
{ multi: true }
)

コレクション内の結果ドキュメントは次のとおりです。

[
{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : {
"publisher" : "2222",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : true
}
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 10,
"info" : { "publisher" : "2255", "pages" : 150 },
"tags" : [ "baking", "cooking" ],
"reorder" : true
}
]

この操作は、次の SQL ステートメントに対応しています。

UPDATE books
SET reorder=true
WHERE stock <= 10

置換を実行し、更新ドキュメントに field:value の式のみが含まれている場合は、multi: true を指定できません。

Tip

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

オプションupsert: trueを指定した場合

  • ドキュメントがクエリ条件に一致する場合、db.collection.update() は更新を実行します。

  • クエリ条件に一致するドキュメントがない場合、db.collection.update()1 つのドキュメントを挿入します。

    注意

    複数の同一のアップサートがほぼ同時に発行されると、upsert: true で使用される update() によって重複したドキュメントが作成される可能性があります。詳細については、「重複した値を使用したアップサート」を参照してください。

シャーディングされたコレクションで upsert: true を指定する場合、filter には完全なシャードキーを含める必要があります。シャーディングされたコレクションにおける追加のdb.collection.update()動作については、シャーディングされたコレクションを参照してください。

次のタブでは、update() を使用したupsert 修飾子のさまざまな使用方法を紹介します。

クエリ条件に一致するドキュメントがなく、<update> パラメーターが置換ドキュメント(フィールドと値のペアのみを含むドキュメント)の場合、更新により、置換ドキュメントのフィールドと値を含む新しいドキュメントが挿入されます。

  • クエリ パラメーターまたは置換ドキュメントのいずれかに_id フィールドを指定した場合、MongoDB は、挿入されるドキュメントでその _id フィールドを使用します。

  • クエリ パラメーターまたは置換ドキュメントのいずれにも_id フィールドを指定しない場合、MongoDB は、ランダムに生成された ObjectId 値を持つ _id フィールドを追加します。

    クエリ パラメーターと置換ドキュメントで異なる _id フィールド値を指定することはできません。指定すると、操作はエラーを返します。

例えば、次の更新では、アップサート オプションが true に設定されます。

db.books.update(
{ item: "ZZZ135" }, // Query parameter
{ $set:
{
item: "ZZZ135", stock: 5, tags: [ "database" ] // Replacement document
}
},
{ upsert: true } // Options
)

<query>パラメータに一致するドキュメントがない場合、更新操作により、置換ドキュメントのみを含むドキュメントが挿入されます。 置換ドキュメントまたはクエリ ドキュメントでは_idフィールドが指定されていないため、操作によって新しいドキュメントの_idフィールドに一意のObjectIdが作成されます。 操作のWriteResultに反映されたupsertが確認できます。

WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5da78973835b2f1c75347a83")
})

この操作により、次のドキュメントが books コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。

{
"_id" : ObjectId("5da78973835b2f1c75347a83"),
"item" : "ZZZ135",
"stock" : 5,
"tags" : [ "database" ]
}

クエリ条件に一致するドキュメントがなく、<update> パラメーターが更新演算子式を含むドキュメントである場合、この操作はでは、<query> パラメーターの等価句から基本ドキュメントを作成し、<update> パラメーターの式を適用します。

<query>からの比較操作は新しいドキュメントに含まれません。 新しいドキュメントに_idフィールドが含まれていない場合、MongoDB はObjectId値を持つ_idフィールドを追加します。

例えば、次の更新では、アップサート オプションが true に設定されます。

db.books.update(
{ item: "BLP921" }, // Query parameter
{ // Update document
$set: { reorder: false },
$setOnInsert: { stock: 10 }
},
{ upsert: true } // Options
)

クエリ条件に一致するドキュメントがない場合、この操作により次のドキュメントが挿入されます( ObjectId値はそれぞれ異なります)。

{
"_id" : ObjectId("5da79019835b2f1c75348a0a"),
"item" : "BLP921",
"reorder" : false,
"stock" : 10
}

Tip

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

<update> パラメーターが 集計パイプライン の場合、更新により、<query> パラメーターの等価句から基本ドキュメントを作成し、そのドキュメントにパイプラインを適用して挿入するドキュメントを作成します。新しいドキュメントに _id フィールドが含まれていない場合、MongoDB は ObjectId 値を持つ _id フィールドを追加します。

たとえば、次のupsert: true操作は、使用する集計パイプラインを指定します

  • $replaceRoot ステージ、これは $setOnInsert 更新演算子式と似た動作を提供できます。

  • $set ステージは、$set 更新演算子式と同様に動作します。

  • NOW 集計変数は現在の日時に設定し、$currentDate 更新演算子式と同様の動作を提供できます。

db.books.update(
{ item: "MRQ014", ratings: [2, 5, 3] }, // Query parameter
[ // Aggregation pipeline
{ $replaceRoot: { newRoot: { $mergeObjects: [ { stock: 0 }, "$$ROOT" ] } } },
{ $set: { avgRating: { $avg: "$ratings" }, tags: [ "fiction", "murder" ], lastModified: "$$NOW" } }
],
{ upsert: true } // Options
)

<query> パラメーターに一致するドキュメントがない場合、この操作により次のドキュメントが books コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。

{
"_id" : ObjectId("5e2921e0b4c550aad59d1ba9"),
"stock" : 0,
"item" : "MRQ014",
"ratings" : [ 2, 5, 3 ],
"avgRating" : 3.3333333333333335,
"tags" : [ "fiction", "murder" ],
"lastModified" : ISODate("2020-01-23T04:32:32.951Z")
}

Tip

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

集計パイプラインを使用した更新の追加例については、集約パイプラインを使用した更新を参照してください。

mongoshから、次のドキュメントをbooksコレクションに挿入します。

db.books.insertMany( [
{
_id: 5,
item: "RQM909",
stock: 18,
info: { publisher: "0000", pages: 170 },
reorder: true
},
{
_id: 6,
item: "EFG222",
stock: 15,
info: { publisher: "1111", pages: 72 },
reorder: true
}
] )

次の操作では、multi オプションと upsert オプションの両方を指定します。一致するドキュメントが存在する場合、この操作により一致するすべてのドキュメントが更新されます。一致するドキュメントが存在しない場合は、この操作によって新しいドキュメントが挿入されます。

db.books.update(
{ stock: { $gte: 10 } }, // Query parameter
{ // Update document
$set: { reorder: false, tags: [ "literature", "translated" ] }
},
{ upsert: true, multi: true } // Options
)

この操作により、一致するすべてのドキュメントが更新され、次の結果になります。

{
"_id" : 5,
"item" : "RQM909",
"stock" : 18,
"info" : { "publisher" : "0000", "pages" : 170 },
"reorder" : false,
"tags" : [ "literature", "translated" ]
}
{
"_id" : 6,
"item" : "EFG222",
"stock" : 15,
"info" : { "publisher" : "1111", "pages" : 72 },
"reorder" : false,
"tags" : [ "literature", "translated" ]
}

コレクションに一致するドキュメントがない場合、この操作を行うと、<query><update> の両方の仕様のフィールドを使用して単一のドキュメントが挿入されます。例えば、次の操作について考えてみましょう。

db.books.update(
{ "info.publisher": "Self-Published" }, // Query parameter
{ // Update document
$set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 }
},
{ upsert: true, multi: true } // Options
)

この操作により、次のドキュメントが books コレクションに挿入されます(ObjectId 値はそれぞれ異なります)。

{
"_id" : ObjectId("5db337934f670d584b6ca8e0"),
"info" : { "publisher" : "Self-Published" },
"reorder" : false,
"stock" : 25,
"tags" : [ "literature", "hardcover" ]
}

upsert: true を指定してupdate() を実行して、クエリが既存のドキュメントと一致しない場合、クエリがドット表記を使用して _id フィールドに条件を指定すると、MongoDB は新しいドキュメントの挿入を拒否します。

この制限により、_id ドキュメントに埋め込まれたフィールドの順序が明確に定義され、クエリで指定された順序に縛られることがなくなります。

この方法でドキュメントを挿入しようとすると、MongoDB でエラーが発生します。例えば、次の更新操作について考えてみましょう。更新操作で upsert:true を指定し、クエリでドット表記を使用してフィールドに条件を指定しているため、挿入するドキュメントを作成する際にエラーが発生します。

db.collection.update(
{ "_id.name": "Robert Frost", "_id.uid": 0 }, // Query parameter
{ $set:
{
"categories": [ "poet", "playwright" ] // Replacement document
}
},
{ upsert: true } // Options
)

WriteResult 操作では、次のエラーが返されます。

WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 111,
"errmsg" : "field at '_id' must be exactly specified, field at sub-path '_id.name'found"
}
})

Tip

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

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

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

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

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

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

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

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

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

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

    • 更新操作が 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)と一致しないため、操作は失敗します。

Tip

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

db.collection.update() メソッドでは、集計パイプライン [ <stage1>, <stage2>, ... ] を受け入れて、実行する変更を指定できます。このパイプラインには次のステージが含まれる可能性があります。

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

次のドキュメントを使用して students コレクションを作成します。

db.students.insertMany( [
{ "_id" : 1, "student" : "Skye", "points" : 75, "commentsSemester1" : "great at math", "commentsSemester2" : "loses temper", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "students" : "Elizabeth", "points" : 60, "commentsSemester1" : "well behaved", "commentsSemester2" : "needs improvement", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
] )

commentsSemester1 フィールドと commentsSemester2 フィールドを別々にするのではなく、これらを新しい comments フィールドにまとめるとします。次に示す更新操作では、集計パイプラインを使用して次のようにします。

  • 新しいcommentsフィールドを追加し、 lastUpdateフィールドを設定します。

  • コレクション内にあるすべてのドキュメントのcommentsSemester1フィールドとcommentsSemester2フィールドを削除します。

db.members.update(
{ },
[
{ $set: { comments: [ "$commentsSemester1", "$commentsSemester2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "commentsSemester1", "commentsSemester2" ] }
],
{ multi: true }
)

注意

パイプライン内で使用される $set$unset は、集計ステージの$set$unset をそれぞれ示しており、アップデートの演算子の$set$unset ではありません。

第 1 ステージ

$set段階:

  • 新しい配列フィールドcommentsを作成します。その要素としてcommentsSemester1フィールドとcommentsSemester2フィールドの現在の内容を含めます。

  • フィールドlastUpdateを集計変数NOWの値に設定します。集計変数 NOW は現在の日時値に変換され、パイプライン全体で維持されます。集計変数にアクセスするには、変数の前に二重ドル記号$$を付け、引用符で囲みます。

第 2 ステージ
$unsetステージでは、 commentsSemester1フィールドとcommentsSemester2フィールドが削除されます。

コマンドの実行後、コレクションには次のドキュメントが含まれます。

{ "_id" : 1, "student" : "Skye", "status" : "Modified", "points" : 75, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "great at math", "loses temper" ] }
{ "_id" : 2, "student" : "Elizabeth", "status" : "Modified", "points" : 60, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "well behaved", "needs improvement" ] }

Tip

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

次のドキュメントを使用して students3 コレクションを作成します。

db.students3.insertMany( [
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
] )

集計パイプラインを使用すると、計算されたグレード平均およびレターグレードでドキュメントを更新することができます。

db.students3.update(
{ },
[
{ $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] }, lastUpdate: "$$NOW" } },
{ $set: { grade: { $switch: {
branches: [
{ case: { $gte: [ "$average", 90 ] }, then: "A" },
{ case: { $gte: [ "$average", 80 ] }, then: "B" },
{ case: { $gte: [ "$average", 70 ] }, then: "C" },
{ case: { $gte: [ "$average", 60 ] }, then: "D" }
],
default: "F"
} } } }
],
{ multi: true }
)

注意

パイプラインで使用される$setは、アップデートオペレーターの $set ではなく、集計ステージ $setを参照します。

第 1 ステージ

$set段階:

  • testsフィールドの平均に基づいて新しいフィールドaverageを計算します。$avg集計演算子の詳細については$avgを参照してください。 $trunc切り捨て集計演算子の詳細については$truncを参照してください。

  • フィールドlastUpdateを集計変数NOWの値に設定します。集計変数 NOW は現在の日時値に変換され、パイプライン全体で維持されます。集計変数にアクセスするには、変数の前に二重ドル記号$$を付け、引用符で囲みます。

第 2 ステージ
$setステージでは、前のステージで計算されたaverageフィールドに基づいて新しいフィールドgradeが計算されます。集計演算子 $switch の詳細については、$switch を参照してください。

コマンドの実行後、コレクションには次のドキュメントが含まれます。

{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 92, "grade" : "A" }
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 90, "grade" : "A" }
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 75, "grade" : "C" }

Tip

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

アップデート ドキュメントでは、$[<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パラメーターを使用します。

mongosh で、次のドキュメントを含む 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.students.update(
{ grades: { $gte: 100 } },
{ $set: { "grades.$[element]" : 100 } },
{
multi: true,
arrayFilters: [ { "element": { $gte: 100 } } ]
}
)

操作後、コレクションには次のドキュメントが含まれます。

{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 100 ] }
{ "_id" : 3, "grades" : [ 95, 100, 100 ] }

また、arrayFilters パラメータを使用して、ドキュメントの配列内の特定のドキュメント フィールドを更新することもできます。

mongosh で、次のドキュメントを含む 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 }
]
}
] )

grades 配列のすべての要素のうち、グレードが 85 以上のもので mean フィールドの値を変更するには、フィルタリングされた位置演算子 $[<identifier>]arrayFilters とともに使用します。

db.students2.update(
{ },
{ $set: { "grades.$[elem].mean" : 100 } },
{
multi: true,
arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
}
)

操作後、コレクションには次のドキュメントが含まれます。

{
"_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" : 100, "std" : 6 },
{ "grade" : 87, "mean" : 100, "std" : 3 },
{ "grade" : 85, "mean" : 100, "std" : 4 }
]
}

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

db.newStudents.insertMany( [
{ "_id" : 1, "student" : "Richard", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 2, "student" : "Jane", "grade" : "A", "points" : 60, "comments1" : "well behaved", "comments2" : "fantastic student" },
{ "_id" : 3, "student" : "Ronan", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 4, "student" : "Noah", "grade" : "D", "points" : 20, "comments1" : "needs improvement", "comments2" : null },
{ "_id" : 5, "student" : "Adam", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 6, "student" : "Henry", "grade" : "A", "points" : 86, "comments1" : "fantastic student", "comments2" : "well behaved" }
] )

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

db.newStudents.createIndex( { grade: 1 } )

次の更新操作では、インデックス {grade: 1 } を使用するようにヒントを明示的に示しています

db.newStudents.update(
{ points: { $lte: 20 }, grade: "F" }, // Query parameter
{ $set: { comments1: "failed class" } }, // Update document
{ multi: true, hint: { grade: 1 } } // Options
)

注意

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

update コマンドは次を返します。

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })

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

db.newStudents.explain().update(
{ "points": { $lte: 20 }, "grade": "F" },
{ $set: { "comments1": "failed class" } },
{ multi: true, hint: { grade: 1 } }
)

db.collection.explain().update()はドキュメントを変更しません。

バージョン 5.0 で追加

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

注意

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

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

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

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

db.cakeFlavors.update(
{ $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } },
[ { $set: { flavor: "$$newFlavor" } } ],
{ let : { targetFlavor: "cherry", newFlavor: "orange" } }
)

次のレプリカセットに対する操作では、w: 2書込み保証 (write concern)を指定し、タイムアウトを wtimeout で5000 ミリ秒に設定しています。この操作は、書き込み (write) がプライマリと1つのセカンダリの両方に伝達された後に返すか、5 秒後にタイムアウトします。

db.books.update(
{ stock: { $lte: 10 } },
{ $set: { reorder: true } },
{
multi: true,
writeConcern: { w: 2, wtimeout: 5000 }
}
)

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

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

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

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

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

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

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

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

mongoshで、次のドキュメントを含む myColl という名前のコレクションを作成します。

db.myColl.insertMany( [
{ _id: 1, category: "café", status: "A" },
{ _id: 2, category: "cafe", status: "a" },
{ _id: 3, category: "cafE", status: "a" }
] )

次の操作には照合オプションが付いており、multitrue に設定しているので、一致するドキュメントがすべて更新されます。

db.myColl.update(
{ category: "cafe" },
{ $set: { status: "Updated" } },
{
collation: { locale: "fr", strength: 1 },
multi: true
}
)

操作の書込み結果として、コレクション内の 3 つのドキュメントがすべて更新されたことを示す次のドキュメントが返されます。

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })

操作後、コレクションには次のドキュメントが含まれます。

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

db.collection.update() メソッドは、操作のステータスを含む WriteResult() オブジェクトを返します。成功すると、WriteResult() オブジェクトには、クエリ条件に一致したドキュメントの数、更新によって挿入されたドキュメントの数、および変更されたドキュメントの数が含まれます。

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

db.collection.update()メソッドで書込み保証 (write concern) が発生した場合、結果にはWriteResult.writeConcernErrorフィールドが含まれます。

WriteResult({
"nMatched" : 1,
"nUpserted" : 0,
"nModified" : 1,
"writeConcernError": {
"code" : 64,
"errmsg" : "waiting for replication timed out",
"errInfo" : {
"wtimeout" : true,
"writeConcern" : {
"w" : "majority",
"wtimeout" : 100,
"provenance" : "getLastErrorDefaults"
}
}
})

次の表は、WriteResult.writeConcernError.provenanceの値について説明したものです。

出所
説明
clientSupplied
書き込み保証(write concern)がアプリケーションで指定されました。
customDefault
書込み保証 (write concern) は、カスタム定義されたデフォルト値に基づきます。setDefaultRWConcern を参照してください。
getLastErrorDefaults
書込み保証 (write concern) は、レプリカセットの settings.getLastErrorDefaults のフィールドに基づきます。
implicitDefault
他の書き込み保証(write concern)が一切指定されていない状態で、サーバーから発生した書き込み保証。

Tip

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

db.collection.update() メソッドで書込み保証(write concern)エラーが発生した場合、結果には WriteResult.writeError フィールドが含まれます。

WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 7,
"errmsg" : "could not contact primary for replica set shard-a"
}
})

Tip

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

戻る

db.collection.unhideIndex