Можете да $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, тези опции няма да бъдат предадени на сървъра от тази програма. Препоръчително е да останете само с обвивката и поддържаните продукти, въпреки че има някои други предложения, които нямат същото ограничение.