sql >> Databasteknik >  >> NoSQL >> MongoDB

mongoDB upsert på array

Detta är inte riktigt så enkelt som man kan tro, och faktiskt är det intressant att du har delat upp din analys av detta i tre delar. För, gissa vad? Det är precis vad du måste do. Låt oss överväga stegen:

1. Infoga ett dokument om det inte finns

db.collection.update(
    { 
        "clientId":"123456"
    },
    {
        "$setOnInsert": {
            "clientId": "123456",
            "devices": [{
                "deviceId": "321",
                "deviceType" : "kindle",
                "notification" : false
            }]
        }
    },
    { "upsert": true }
)

Så vad du vill göra är att infoga ett nytt dokument där "clientId" för närvarande inte finns. Detta kan göras som en "upsert" för att undvika möjliga unika nyckelkrockar och även där det inte finns någon "unik" restriktion, så säkerställer "upsert"-karaktären att du bara skapar det "nya" dokumentet när det inte hittades. Det finns också $setOnInsert här för att du inte vill göra vad som helst med ett dokument som "hittas" vid det här laget.

Observera här att det finns nej försök att matcha elementet i arrayen. Detta beror på att du sannolikt inte vill "skapa" ett nytt dokument bara för att ett befintligt inte har "det" arrayelementet. Vilket tar oss till nästa steg.

2. Uppdatera innehållet i dokumentet där det finns

db.collection.update(
    { 
        "clientId":"123456",
        "devices": { "$elemMatch": { "deviceId" : "321" } }
    },
    {
        "$set": {
            "devices.$.deviceType" : "kindle",
            "devices.$.notification" : false
        }
    }
)

Nu här vill du faktiskt försöka "matcha" dokumentet för "clientId" som gör innehåller ett element i arrayen som också matchar "deviceId" du letar efter. Så genom att ange ett villkor som ska matcha, får du användningen av positionen $ operatör för att ställa in fälten i "matchande" position.

Som ovan skulle detta antingen matcha ett sak eller ingenting så antingen gjordes uppdateringen eller så var den inte. Så det går till vår sista del av kaskaden här:

3. Lägg till arrayelementet där det inte finns

db.collection.update(
    { 
        "clientId":"123456"
    },
    {
        "$addToset": { "devices": {
            "deviceId" : "321",
            "deviceType" : "kindle",
            "notification" : false
        }}
    }
)

Så det här är viktigt sista etappen. Anledningen är att om någon av de föregående operationerna gjorde "skapa" eller "uppdatera" det befintliga dokumentet, använd sedan $addToSet här gör du säker du "skjuter" inte ett annat dokument till arrayen med samma "deviceId" men andra olika värden. Om en av dessa stadier fungerade, skulle detta se att alla värden för det elementet redan existerade och sedan inte lägga till ytterligare ett.

Om du försökte göra det i en annan ordning skulle du ha två i det fall du presenterar dokument i arrayen med samma "deviceId", men olika värden för "deviceType" och "notification". Så det är därför det kommer sist.

Slutsats

Så tyvärr finns det inget enkelt sätt att kombinera dessa som ett drift. Operatörerna finns helt enkelt inte så att detta skulle kunna göras i ett enda uttalande och därför måste utför tre uppdatera operationer för att göra vad du vill. Också som sagt, ordern tillämpning för dessa uppdateringar är viktigt så att du får önskat resultat.

Även om detta inte existerar ännu i nuvarande "produktions"-utgåvor, har den kommande utgåvan (2.6 och uppåt i skrivande stund) ett sätt att "batcha" dessa förfrågningar med en ny syntax att uppdatera:

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
                }}
            }
        }
    ]
)

Så medan det fortfarande är i huvudsak tre operationer, åtminstone får du skicka dem över tråden bara en gång



  1. varför går det så långsamt med 100 000 poster när man använder pipeline i redis?

  2. mongo.so:> odefinierad symbol:php_json_encode in Okänd på rad 0. Efter installationen mongo drivrutin för php

  3. Node.js filuppladdning (Express 4, MongoDB, GridFS, GridFS-Stream)

  4. Introduktion till Redis Cluster Sharding – Fördelar, begränsningar, distribution och klientanslutningar