sql >> Databasteknik >  >> NoSQL >> MongoDB

Ta bort objekt från kapslad array enligt flera kriterier

Du kan $pull den "första matchningen" från den "yttre arrayen" med att ta bort "alla inre element" helt enkelt genom att göra:

db.Events.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$.DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

Det är bra om du bara har en post i "Distributions" array eller åtminstone en av dessa poster har underordnade arrayposter som skulle matcha villkoret. Så här är positionsbestämningen $ Operator fungerar med alla versioner av MongoDB.

Om data skulle ha "flera" matchningar i den "yttre" "Distributions" array, om du har MongoDB 3.6 kan du använda den positionsfiltrerade $[<identifier>] operatör för att ändra alla matchade poster:

db.Events.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$[element].DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "arrayFilters": [
      { "element.DistributionData": {
        "$elemMatch": {
          "Key": null,
          "Value": null,
          "Children": null
        }
      }}
    ]
  }
)

I så fall arrayFilters option definierar ett villkor genom vilket vi matchar poster i den "yttre" arrayen så att detta faktiskt kan gälla allt som matchas.

Eller faktiskt sedan $pull i huvudsak har dessa villkor i sig, då kan du alternativt bara använda positions-all $[] operatör i detta fall:

db.Event.updateMany(
  {
    "Distributions.DistributionData": {
      "$elemMatch": {
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  },
  {
    "$pull": {
      "Distributions.$[].DistributionData": { 
        "Key": null,
        "Value": null,
        "Children": null
      }
    }
  }
)

Båda fallen ändrar dokumentet i frågan genom att ta bort det inre objektet med alla null nycklar:

{
        "_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
        "CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
        "WKT" : "",
        "Distributions" : [
                {
                        "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                        "DeliveryType" : 1,
                        "DistributionData" : [
                                {
                                        "Key" : "Topic",
                                        "Value" : "Topics",
                                        "Children" : null
                                },
                                {
                                        "Key" : "Message",
                                        "Value" : "test",
                                        "Children" : null
                                }
                        ],
                        "Schedules" : [
                                ISODate("2016-05-06T05:09:56.988Z")
                        ]
                }
        ]
}

"Frågevillkoren" använder alla $elemMatch för val av dokument. Detta krävs faktiskt för den positionella $ operatör för att erhålla det "positionsindex" som används för den "första matchningen". Även om detta faktiskt inte är ett "krav" för varken den positionsfiltrerade $[<identifier>] eller positionella alla $[] operatör, är det fortfarande användbart så att du inte ens överväger dokument för uppdatering som inte kommer att matcha de senare uppdateringsvillkoren för antingen $pull eller arrayFilters alternativ.

När det gäller $pull i sig gäller villkoren här faktiskt för "varje" arrayelement, så det finns inget behov av $elemMatch i den operationen eftersom vi redan tittar på "element"-nivån.

Det tredje exemplet visar att den positionella alla $[] operatören kan helt enkelt använda dessa $pull villkor med hänsyn till varje "inre" matriselement och kommer bara att gälla för ALLA "yttre" matriselement. Så den faktiska punkten för den positionsfiltrerade $[<identifier>] uttrycket är att "bara" bearbeta de "yttre" arrayelementen som faktiskt matchar det "inre" tillståndet. Därför använder vi $elemMatch i övervägandet för att matcha varje "inre" arrayelement.

Om du faktiskt inte har MongoDB 3.6 åtminstone så använder du det första formuläret och upprepar sannolikt det tills uppdateringarna äntligen inte returnerar fler modifierade dokument som indikerar att det inte finns fler element kvar som matchar villkoret.

Det finns en mycket mer detaljerad beskrivning av "alternativen" som tillvägagångssätt i Hur man uppdaterar flera arrayelement i mongodb, men så länge som dina data antingen passar det ursprungliga fallet eller du faktiskt har MongoDB 3.6 tillgängligt, så är detta rätt här.

Om du vill se den fulla effekten av den nya syntaxen för MongoDB 3.6. detta är ändringen av dokumentet i frågan som jag använde för att verifiera uppdateringssatserna här:

{
    "_id" : UUID("cf397865-c000-4f51-8959-1aae84769706"),
    "CreationDateTime" : ISODate("2016-05-06T05:09:14.589Z"),
    "WKT" : "",
    "Distributions" : [
            {
                    "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                    "DeliveryType" : 1,
                    "DistributionData" : [
                            {
                                    "Key" : "Topic",
                                    "Value" : "Topics",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            },
                            {
                                    "Key" : "Message",
                                    "Value" : "test",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            }
                    ],
                    "Schedules" : [
                            ISODate("2016-05-06T05:09:56.988Z")
                    ]
            },
            {
                    "_id" : UUID("bb95bedb-4baa-4ada-90b1-0d763e70ebfe"),
                    "DeliveryType" : 1,
                    "DistributionData" : [
                            {
                                    "Key" : "Topic",
                                    "Value" : "Topics",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            },
                            {
                                    "Key" : "Message",
                                    "Value" : "test",
                                    "Children" : null
                            },
                            {
                                    "Key" : null,
                                    "Value" : null,
                                    "Children" : null
                            }
                    ],
                    "Schedules" : [
                            ISODate("2016-05-06T05:09:56.988Z")
                    ]
            }
    ]
}

Vilket i princip duplicerar vissa poster både "yttre" och "inre" för att visa hur uttalandet tar bort alla null värden.

OBS arrayFilters anges i "options"-argumentet för .update() och liknande metoder är syntaxen i allmänhet kompatibel med alla senaste versioner av drivrutiner och till och med de före lanseringen av MongoDB 3.6.

Detta är dock inte sant för mongo skal, eftersom metoden är implementerad där ("ironiskt nog för bakåtkompatibilitet") arrayFilters argumentet känns inte igen och tas bort av en intern metod som analyserar alternativen för att leverera "bakåtkompatibilitet" med tidigare MongoDB-serverversioner och en "legacy" .update() API-anropssyntax.

Så om du vill använda kommandot i mongo skal eller andra "skalbaserade" produkter (särskilt Robo 3T) behöver du en senaste version från antingen utvecklingsgrenen eller produktionsversionen från och med 3.6 eller senare.

Robo 3T, särskilt här, är fortfarande bunden till att vara baserad på ett MongoDB 3.4-skal. Så även när du ansluter till en kapabel MongoDB 3.6-instans kommer dessa alternativ inte att skickas till servern från det här programmet. Det rekommenderas att bara stanna kvar med skalet och produkter som stöds, även om det finns andra erbjudanden som inte har samma begränsning.




  1. Transaktioner i MongoDB

  2. Spring Boot redis Template autokabelkoppling misslyckades

  3. Allvarligt fel:Klass 'MongoDB\Driver\Manager' hittades inte

  4. MongoDB - Fel:kommandot getMore misslyckades:Markören hittades inte