sql >> Database teknologi >  >> NoSQL >> MongoDB

mongoDB upsert på array

Dette er egentlig ikke så simpelt, som du måske tror, ​​og faktisk er det interessant, at du har delt din analyse af dette op i tre dele. Fordi, gæt hvad? Det er præcis, hvad du skal gør. Lad os overveje trinene:

1. Indsæt et dokument, hvis et ikke findes

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

Så det, du vil gøre, er at indsætte et nyt dokument, hvor "clientId" i øjeblikket ikke eksisterer. Dette kan gøres som en "upsert" for at undgå mulige unikke nøglesammenstød, og selv hvor der ikke er nogen "unik" begrænsning, så sikrer "upsert" karakteren af ​​dette, at du kun opretter det "nye" dokument, når det ikke blev fundet. Der er også $setOnInsert her, fordi du ikke ønsker at gøre noget ved et dokument, der er "fundet" på dette tidspunkt.

Bemærk her, at der er ingen forsøg på at matche elementet i arrayet. Dette er fordi du sandsynligvis ikke ønsker at "oprette" et nyt dokument, bare fordi et eksisterende ikke havde "det" array-element. Hvilket bringer os til næste trin.

2. Opdater indholdet af dokumentet, hvor det findes

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

Her vil du faktisk prøve at "matche" dokumentet for det "clientId", der gør indeholde et element i arrayet, der også matcher det "deviceId", du leder efter. Så ved at angive en betingelse, der skal matche, får du brugen af ​​den positionelle $ operatør for at sætte felterne i "matchende" position.

Som ovenfor skulle dette enten matche én ting eller intet så enten blev opdateringen udført, eller også var den ikke. Så det flytter til vores sidste del af kaskaden her:

3. Tilføj array-elementet, hvor det ikke findes

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

Så det er vigtigt sidste etape. Årsagen er, at hvis en af ​​de foregående operationer gjorde "opret" eller "opdater" det eksisterende dokument, derefter brugen af ​​$addToSet her gør sikker du "skubber" ikke et andet dokument til arrayet med det samme "deviceId", men andre forskellige værdier. Hvis en af disse stadier fungerede, ville dette se, at alle værdierne af det element allerede eksisterede, og ville derefter ikke tilføje endnu en.

Hvis du forsøgte at gøre det i en anden rækkefølge, ville du i det tilfælde, du præsenterer, have to dokumenter i arrayet med det samme "deviceId", men forskellige værdier for "deviceType" og "notification". Så derfor kommer det sidst.

Konklusion

Så der er desværre ingen enkel måde at kombinere disse som én operation. Operatørerne eksisterer simpelthen ikke, så dette kunne gøres i en enkelt erklæring, og derfor skal udføre tre opdatere operationer for at gøre, hvad du vil. Også som nævnt er ordren anvendelsen af ​​disse opdateringer er vigtig så du får det ønskede resultat.

Selvom dette ikke eksisterer endnu i nuværende "produktions"-udgivelser, har den kommende udgivelse (2.6 og nyere i skrivende stund) en måde at "batch" disse anmodninger med en ny syntaks, der skal opdateres:

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å mens det stadig er i det væsentlige tre operationer, i det mindste kan du sende dem over ledningen kun én gang



  1. Hvorfor udløber Redis-nøgler ikke?

  2. Sådan eksporteres MongoDB-forespørgselsresultater til en JSON-fil

  3. Kan det betale sig at forkorte MongoDB ejendomsnavne?

  4. MongoDB:Hvordan opdaterer jeg et enkelt underelement i et array, refereret af indekset i arrayet?