MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Премахване на обект от вложен масив по множество критерии

Можете да $pull "първото съвпадение" от "външния масив" с премахване на "всички вътрешни елементи" просто като направите:

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

Това е добре, ако някога имате само един запис в "Distributions" масив или поне само един от тези записи има записи в дъщерния масив, които биха отговаряли на условието. Ето как позиционният $ оператор работи с всички версии на MongoDB.

Ако данните биха имали „множество“ съвпадения във „външното“ "Distributions" тогава, ако имате MongoDB 3.6, можете да приложите филтрирания по позиция $[<identifier>] оператор за промяна на всички съвпадащи записи:

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

В този случай arrayFilters опцията дефинира условие, при което съпоставяме записи във "външния" масив, така че това всъщност да може да се приложи за всичко, което е съпоставено.

Или наистина от $pull по същество има самите тези условия, тогава можете алтернативно просто да използвате позиционния all $[] оператор в този случай:

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

Всеки случай променя документа във въпроса, като премахва вътрешния елемент с всички null клавиши:

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

Всички условия за "заявка" използват $elemMatch за избор на документ. Това всъщност се изисква за позиционния $ оператор, за да се получи "индексът на позицията", използван за "първото съвпадение". Макар че това всъщност не е „изискване“ нито за позиционно филтрирания $[<identifier>] или позиционното всички $[] оператор, той все още е полезен, така че дори не разглеждате документи за актуализиране, които няма да съответстват на по-късните условия за актуализиране на $pull или arrayFilters опции.

Що се отнася до $pull условията тук всъщност се прилагат за "всеки" елемент на масива, така че няма нужда от $elemMatch в тази операция, тъй като вече разглеждаме ниво "елемент".

Третият пример показва, че позиционният all $[] операторът може просто да използва тези $pull условия, като се има предвид всеки "вътрешен" елемент на масива и ще се прилага само за ВСИЧКИ "външни" елементи на масива. Така че действителната точка на позиционния филтриран $[<identifier>] изразът е да обработва "само" онези "външни" елементи на масива, които действително отговарят на "вътрешното" условие. Ето защо ние използваме $elemMatch в съображението за съвпадение на всеки "вътрешен" елемент на масива.

Ако всъщност нямате MongoDB 3.6 поне, тогава използвате първия формуляр и вероятно го повтаряте, докато най-накрая актуализациите не върнат повече модифицирани документи, показващи, че не са останали повече елементи, които отговарят на условието.

Има много по-подробно описание за "алтернативите" като подходи в Как да актуализирате множество елементи на масив в mongodb, но стига данните ви да отговарят на първоначалния случай или всъщност имате налична MongoDB 3.6, тогава това е правилното подход тук.

Ако искате да видите пълния ефект от новия синтаксис за MongoDB 3.6. това е промяната на документа във въпроса, който използвах за проверка на изявленията за актуализиране тук:

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

Което по същество дублира някои записи както "външни", така и "вътрешни", за да покаже как изявлението премахва всички null стойности.

ЗАБЕЛЕЖКА arrayFilters са посочени в аргумента "опции" за .update() и подобно на методите, синтаксисът обикновено е съвместим с всички последни версии на драйвери и дори тези преди пускането на MongoDB 3.6.

Това обаче не е вярно за mongo shell, тъй като начина, по който методът е внедрен там ( "по ирония на съдбата за обратна съвместимост" ), arrayFilters аргументът не се разпознава и премахва от вътрешен метод, който анализира опциите, за да осигури "обратна съвместимост" с предишни версии на сървъра на MongoDB и "наследен" .update() Синтаксис на извикване на API.

Така че, ако искате да използвате командата в mongo shell или други продукти, базирани на черупки (по-специално Robo 3T), имате нужда от най-новата версия или от клона за разработка, или от производствената версия от 3.6 или по-нова версия.

Robo 3T по-специално тук все още е свързан с основа на обвивка MongoDB 3.4. Така че дори когато се свързвате към способен екземпляр на MongoDB 3.6, тези опции няма да бъдат предадени на сървъра от тази програма. Препоръчително е да останете само с обвивката и поддържаните продукти, въпреки че има някои други предложения, които нямат същото ограничение.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Мониторинг на Percona сървър за MongoDB – ключови показатели

  2. Nodejs Mongo вмъкване в поддокумент - динамично име на поле

  3. Вложена заявка на Mongoose в модел по поле на неговия рефериран модел

  4. Как да върна JSON данни от php MongoCursor

  5. ScaleGrid обявява MongoDB хостинг услуги в Канада