Това всъщност не е толкова просто, колкото може би си мислите, и всъщност е интересно, че сте разделили анализа на това на три части. Защото познайте какво? Точно това е, което виетрябвате направи. Нека разгледаме стъпките:
1. Поставете документ, ако не съществува
db.collection.update(
{
"clientId":"123456"
},
{
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
}
},
{ "upsert": true }
)
Така че това, което искате да направите, е вмъкване нов документ, където "clientId" в момента не съществува. Това може да се направи като "upsert", за да се избегнат възможни уникални сблъсъци на ключове и дори когато няма "уникално" ограничение, тогава естеството на "upsert" на това гарантира, че създавате "нов" документ само когато не е намерен. Също така има $setOnInsert
тук, защото виенете искате да направите нещо с документ, който е "намерен" в този момент.
Обърнете внимание тук, че нямане опитайте се да съпоставите елемента в масива. Това е така, защото вероятно не искате да "създавате" нов документ, само защото съществуващ не е имал "този" елемент на масива. Което ни води до следващата стъпка.
2. Актуализирайте съдържанието на документа, където съществува
db.collection.update(
{
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
{
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
)
Сега тук искате действително да опитате да „съпоставите“ документа за „clientId“, който прави съдържа елемент в масива, който също съответства на "deviceId", който търсите. Така че, като посочите условие за съвпадение, вие получавате използването на позиционния $
оператор, за да зададете полетата в позиция "съвпадение".
Както по-горе, това или щеше да съответства на едно нещо илинищо така че или актуализацията е направена, или не. Така че това преминава към нашата последна част от каскадата тук:
3. Добавете елемента на масива, където не съществува
db.collection.update(
{
"clientId":"123456"
},
{
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
)
Така че това еважно последния етап. Причината е, че ако някоя от предходните операции направи „създайте“ или „актуализирайте“ съществуващия документ, след което използването на $addToSet
тук прависигурно вие не "бутате" друг документ към масива със същия "deviceId", но с други различни стойности. Акоедно от тези етапи работи, тогава това ще види, че всички стойности на този елемент вече съществуват, и след това няма да добави още един.
Ако се опитате да направите това в различен ред, в случая, който представяте, ще имате два документи в масива със същия "deviceId", но различни стойности за "deviceType" и "notification". Затова е последен.
Заключение
Така че, за съжаление, няма лесен начин да ги комбинирате катоедно операция. Операторите просто не съществуват, за да може това да се направи с едно изявление и следователно трябва изпълняваттри актуализирайте операции, за да направите това, което искате. Също както е посочено, напоръчкатата на приложението за тези актуализации е важно така че да получите желания резултат.
Въпреки че това все още не съществува в текущите „производствени“ издания, предстоящата версия (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
}}
}
}
]
)
Така че докато това е все още по същество три операции, поне можете да ги изпратите по кабела само веднъж