これはあなたが思うほど単純ではありません、そして実際にあなたがこれの分析を3つの部分に分けたのは興味深いことです。なぜなら、何だと思いますか?それはまさにあなたがしなければならないものです 行う。手順を考えてみましょう:
1。ドキュメントが存在しない場合は挿入します
db.collection.update(
{
"clientId":"123456"
},
{
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
}
},
{ "upsert": true }
)
だからあなたがしたいのは挿入です 「clientId」が現在存在しない新しいドキュメント。これは、「一意の」キーの衝突を回避するための「アップサート」として実行でき、「一意の」制約がない場合でも、この「アップサート」の性質により、「新しい」ドキュメントが見つからなかった場合にのみ作成できます。 $setOnInsert
もあります ここではしないからです この時点で「見つかった」ドキュメントに対して何かをしたい。
ここではなしがあることに注意してください 配列内の要素を一致させようとします。これは、既存のドキュメントに「その」配列要素がなかったという理由だけで、新しいドキュメントを「作成」したくない可能性があるためです。次のステップに進みます。
2。ドキュメントが存在する場所でドキュメントの内容を更新します
db.collection.update(
{
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
{
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
)
ここで、実際に実行する「clientId」のドキュメントを「照合」してみます。 探している「deviceId」にも一致する要素が配列に含まれています。したがって、一致する条件を指定することで、位置$
を使用できます。 フィールドを「一致する」位置に設定するための演算子。
上記のように、これは1つと一致する予定でした 物または何もない したがって、更新が行われたか、行われなかったかのどちらかです。これで、カスケードの最後の部分に移ります:
3。存在しない配列要素を追加します
db.collection.update(
{
"clientId":"123456"
},
{
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
)
したがって、これは重要 最終段階。その理由は、前述の操作のいずれかが実行された 既存のドキュメントを「作成」または「更新」してから、$addToSet
を使用します ここで確実になります 同じ「deviceId」が他の異なる値を持つ別のドキュメントを配列に「プッシュ」しているのではありません。 1つの場合 これらのステージのうち、機能した場合、その要素のすべての値がすでに存在していることがわかり、別の要素を追加することはありません。
別の順序でそれを行おうとした場合、提示する場合は2つになります 「deviceId」は同じですが、「deviceType」と「notification」の値が異なる配列内のドキュメント。それが最後になる理由です。
結論
残念ながら、これらを1つとして組み合わせる簡単な方法はありません。 手術。演算子は単に存在しないため、これは1つのステートメントで実行できるため、必要 3つを実行します あなたが望むことをするために操作を更新します。また、述べたように、注文 これらの更新の申請の割合は重要です 希望する結果が得られるようにします。
これは現在の「本番」リリースにはまだ存在しませんが、次のリリース(執筆時点では2.6以降)には、更新する新しい構文でこれらの要求を「バッチ処理」する方法があります。
db.runCommand(
"update": "collection",
"updates": [
{
"q": { "clientId":"123456" },
"u": {
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
},
"upsert": true
},
{
"q": {
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
"u": {
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
},
{
"q": { "clientId":"123456" },
"u": {
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
}
]
)
ですから、それはまだ 基本的に3つの操作で、少なくともネットワーク経由で送信できます。 一度だけ