sql >> Databáze >  >> NoSQL >> MongoDB

Odebrat objekt z vnořeného pole podle více kritérií

Můžete $pull „první shoda“ z „vnějšího pole“ s odstraněním „všech vnitřních prvků“ jednoduše takto:

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

To je v pořádku, pokud máte v "Distributions" vždy pouze jeden záznam pole nebo alespoň jedna z těchto položek má podřízené položky pole, které by odpovídaly podmínce. Takto vypadá poziční $ operátor pracuje se všemi verzemi MongoDB.

Pokud by data měla "více" shod ve "vnějším" "Distributions" pole, pak pokud máte MongoDB 3.6, můžete použít pozičně filtrovaný $[<identifier>] operátor pro úpravu všech odpovídajících záznamů:

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

V takovém případě arrayFilters volba definuje podmínku, podle které porovnáváme položky ve "vnějším" poli, takže to může ve skutečnosti platit pro vše, co je srovnáno.

Nebo skutečně od $pull v podstatě má tyto podmínky sám, pak můžete alternativně použít pouze poziční all $[] operátor v tomto případě:

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

V obou případech změní dokument v otázce odstraněním vnitřní položky se všemi null klíče:

{
        "_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")
                        ]
                }
        ]
}

Všechny podmínky "dotazu" používají $elemMatch pro výběr dokumentu. To je ve skutečnosti vyžadováno pro poziční $ operátor za účelem získání "pozičního indexu" použitého pro "první shodu". I když to ve skutečnosti není "požadavek" ani pro pozičně filtrovaný $[<identifier>] nebo poziční vše $[] operátor, je stále užitečný, takže ani neuvažujete o aktualizaci dokumentů, které nebudou odpovídat podmínkám pozdější aktualizace ani $pull nebo arrayFilters možnosti.

Pokud jde o $pull samotné, podmínky zde ve skutečnosti platí pro "každý" prvek pole, takže není potřeba $elemMatch v této operaci, protože se již díváme na úroveň „prvku“.

Třetí příklad ukazuje, že poziční vše $[] operátor může jednoduše použít tyto $pull podmínky s ohledem na každý "vnitřní" prvek pole a bude platit pouze pro VŠECHNY "vnější" prvky pole. Tedy skutečný bod pozičně filtrovaného $[<identifier>] výraz je "pouze" zpracovat ty "vnější" prvky pole, které skutečně odpovídají "vnitřnímu" stavu. Proto používáme $elemMatch v úvahu pro shodu každého "vnitřního" prvku pole.

Pokud ve skutečnosti nemáte alespoň MongoDB 3.6, pak používáte první formulář a pravděpodobně to budete opakovat, dokud aktualizace konečně nevrátí žádné další upravené dokumenty, což naznačuje, že nezůstaly žádné další prvky odpovídající podmínce.

Existuje mnohem podrobnější popis „alternativ“ jako přístupů v How to Update Multiple Array Elements v mongodb, ale pokud vaše data buď vyhovují původnímu případu, nebo skutečně máte k dispozici MongoDB 3.6, pak je to správné. přístup zde.

Pokud chcete vidět plný efekt nové syntaxe pro MongoDB 3.6. toto je změna dokumentu v otázce, kterou jsem použil k ověření prohlášení o aktualizaci zde:

{
    "_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")
                    ]
            }
    ]
}

Což v podstatě duplikuje některé položky „vnější“ i „vnitřní“, aby se ukázalo, jak příkaz odstraní všechny null hodnoty.

POZNÁMKA arrayFilters jsou specifikovány v argumentu "options" pro .update() a podobně jako u metod je syntaxe obecně kompatibilní se všemi nejnovějšími verzemi ovladačů a dokonce i s těmi před vydáním MongoDB 3.6.

To však neplatí pro mongo shell, protože způsob, jakým je tam metoda implementována ( "ironicky pro zpětnou kompatibilitu"), arrayFilters argument není rozpoznán a odstraněn interní metodou, která analyzuje možnosti, aby byla zajištěna "zpětná kompatibilita" s předchozími verzemi serveru MongoDB a "starší" .update() Syntaxe volání API.

Pokud tedy chcete použít příkaz v mongo shell nebo jiné "shell based" produkty (zejména Robo 3T) potřebujete nejnovější verzi buď z vývojové větve nebo z produkčního vydání od 3.6 nebo vyšší.

Zejména Robo 3T je zde stále spojen s tím, že je založen na prostředí MongoDB 3.4. Takže i když se připojujete ke schopné instanci MongoDB 3.6, tyto možnosti nebudou z tohoto programu předány serveru. Doporučuje se zůstat pouze u shellu a podporovaných produktů, i když existují některé další nabídky, které nemají stejná omezení.




  1. Hledání klíčů bez expirace v Redis

  2. Získejte nejnovější záznam MongoDB podle pole data a času

  3. Jak získat více řádků do seznamu odděleného čárkami v SQL

  4. Jak otestovat celer s django na počítači se systémem Windows