ここで実行しようとしているのは、アイテムが存在しない場所でのみ新しいアイテムを配列に追加し、アイテムが存在しない場所で新しいドキュメントを作成することです。 $addToSet
を選択します アイテムを一意にしたいのですが、実際には「a」だけで一意にしたいのです。
したがって、$addToset
それはしません、そしてあなたはむしろ存在する要素を「テスト」する必要があります。しかし、ここでの本当の問題は、それと「アップサート」の両方を同時に行うことはできないということです。必要に応じて配列要素に追加するのではなく、配列要素が見つからない場合は常に新しいドキュメントが作成されるため、ロジックは機能しません。
$addToSet
として設計された現在の操作エラー 配列を「作成」するために使用することはできませんが、既存の配列にメンバーを「追加」するためにのみ使用できます。しかし、すでに述べたように、ロジックの実現には他にも問題があります。
ここで必要なのは、それぞれが期待されるアクションを実行するために「試行」する一連の更新操作です。これは、複数のステートメントでのみ実行できます:
// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
{ "name": "abc" },
{ "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
{ "upsert": true }
)
// $push the element where "a": 1 does not exist
db.test.update(
{ "name": "abc", "config.a": { "$ne": 1 } },
{ "$push": { "config": { "a": 1, "b": 2 } }}
)
// $set the element where "a": 1 does exist
db.test.update(
{ "name": "abc", "config.a": 1 },
{ "$set": { "config.$.b": 2 } }
)
最初の反復で、最初のステートメントはドキュメントを「アップサート」し、アイテムを含む配列を作成します。 「a」要素には指定された値があるため、2番目のステートメントはドキュメントと一致しません。 3番目のステートメントはドキュメントと一致しますが、値が変更されていないため、書き込み操作では変更されません。
ここで入力を"b": 3
異なる応答が得られますが、望ましい結果が得られます:
db.test.update(
{ "name": "abc" },
{ "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
{ "upsert": true }
)
db.test.update(
{ "name": "abc", "config.a": { "$ne": 1 } },
{ "$push": { "config": { "a": 1, "b": 3 } }}
)
db.test.update(
{ "name": "abc", "config.a": 1 },
{ "$set": { "config.$.b": 3 } }
)
したがって、最初のステートメントは"name": "abc"
のドキュメントと一致します。 ただし、有効な操作は「挿入」のみであるため、何も実行されません。 「a」が条件に一致するため、2番目のステートメントは一致しません。 3番目のステートメントは、「a」の値と一致し、一致した要素の「b」を目的の値に変更します。
その後、「a」を配列に存在しない別の値に変更すると、1と3の両方が何もできなくなりますが、2番目のステートメントは、「a」キーによってコンテンツを一意に保ちながら、配列に別のメンバーを追加します。
また、既存のデータから変更を加えずにステートメントを送信すると、もちろん、すべてのアカウントで何も変更されていないという応答が返されます。
それがあなたの操作の仕方です。これは、「注文済み」のバルク で実行できます。 変更または作成されたものに対する有効な応答を持つサーバーからの要求と応答が1つだけになるように操作します。