Ve skutečnosti to není tak jednoduché, jak si možná myslíte, a ve skutečnosti je zajímavé, že jste svou analýzu rozdělil do tří částí. Protože, hádejte co? To je přesně to, co musíte dělat. Zvažme kroky:
1. Vložte dokument, pokud neexistuje
db.collection.update(
{
"clientId":"123456"
},
{
"$setOnInsert": {
"clientId": "123456",
"devices": [{
"deviceId": "321",
"deviceType" : "kindle",
"notification" : false
}]
}
},
{ "upsert": true }
)
Takže to, co chcete udělat, je vložit nový dokument, kde "clientId" aktuálně neexistuje. To lze provést jako „upsert“, aby se předešlo možným jedinečným střetům klíčů, a dokonce i tam, kde neexistuje žádné „jedinečné“ omezení, pak „upsert“ povaha tohoto zajistí, že vytvoříte „nový“ dokument pouze tehdy, když nebyl nalezen. Existuje také $setOnInsert
zde, protože neděláte chcete udělat cokoli s dokumentem, který je v tomto okamžiku „nalezen“.
Všimněte si, že zde není ne pokusit se porovnat prvek v poli. Je to proto, že pravděpodobně nechcete „vytvářet“ nový dokument jen proto, že existující dokument neměl „ten“ prvek pole. Což nás přivádí k dalšímu kroku.
2. Aktualizujte obsah dokumentu tam, kde existuje
db.collection.update(
{
"clientId":"123456",
"devices": { "$elemMatch": { "deviceId" : "321" } }
},
{
"$set": {
"devices.$.deviceType" : "kindle",
"devices.$.notification" : false
}
}
)
Nyní zde chcete skutečně zkusit „přiřadit“ dokument k „clientId“, které dělá obsahovat prvek v poli, který také odpovídá hledanému "deviceId". Takže zadáním podmínky, která se má shodovat, získáte použití pozičního $
operátora, aby se pole nastavila do "odpovídající" pozice.
Jak je uvedeno výše, toto buď odpovídalo jedničce věc nebo nic takže buď aktualizace proběhla, nebo ne. Takže se přesouváme k naší poslední části kaskády zde:
3. Přidejte prvek pole tam, kde neexistuje
db.collection.update(
{
"clientId":"123456"
},
{
"$addToset": { "devices": {
"deviceId" : "321",
"deviceType" : "kindle",
"notification" : false
}}
}
)
Takže to je důležité poslední etapa. Důvodem je to, že pokud některá z předchozích operací provedla "vytvořit" nebo "aktualizovat" existující dokument a poté použít $addToSet
zde ujišťuje „netlačíte“ další dokument do pole se stejným „deviceId“, ale jinými odlišnými hodnotami. Pokud jeden z těchto fází fungovalo, pak by to vidělo, že všechny hodnoty tohoto prvku již existují, a pak by se nepřidávala další.
Pokud byste to zkusili udělat v jiném pořadí, v případě, který uvádíte, měli byste dva dokumenty v poli se stejným "deviceId", ale odlišnými hodnotami pro "deviceType" a "notification". Proto je to poslední.
Závěr
Takže bohužel neexistuje jednoduchý způsob, jak je spojit jako jeden úkon. Operátory prostě neexistují, aby to šlo udělat v jediném příkazu, a proto musíte provést tři aktualizovat operace, abyste mohli dělat, co chcete. Také, jak je uvedeno, objednávka aplikace pro tyto aktualizace je důležité abyste dosáhli požadovaného výsledku.
I když to zatím v aktuálních „produkčních“ vydáních neexistuje, nadcházející vydání (2.6 a vyšší v době psaní) nabízí způsob, jak tyto požadavky „dávkovat“ novou syntaxí k aktualizaci:
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
}}
}
}
]
)
Takže zatímco to je stále v podstatě tři operace, alespoň je můžete poslat po drátě jen jednou