Вы можете $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>]
позиционной фильтрации *1015* , чтобы изменить все совпадающие записи:
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
, по сути, сам имеет эти условия, тогда вы можете поочередно просто использовать оператор позиционный все $[]
в этом случае:
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
с учетом каждого "внутреннего" элемента массива и будет применяться только к ALL «внешние» элементы массива. Таким образом, фактическая точка выражения с позиционной фильтрацией $[<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")
]
}
]
}
Что в основном дублирует некоторые записи как "external", так и "inner", чтобы показать, как оператор удаляет все значения null
.
NOTE arrayFilters
указаны в аргументе "options" для .update()
и аналогичных методов, синтаксис, как правило, совместим со всеми последними версиями драйверов и даже с версиями, предшествующими выпуску MongoDB 3.6. .
Однако это не относится к оболочке mongo
, так как при реализации метода там («по иронии судьбы для обратной совместимости») аргумент arrayFilters
не распознается и удаляется внутренним методом, который анализирует параметры в чтобы обеспечить «обратную совместимость» с предыдущими версиями сервера MongoDB и «устаревший» .update()
синтаксис вызова API.
Таким образом, если вы хотите использовать команду в оболочке mongo
или других продуктах, основанных на «оболочке» (особенно Robo 3T), вам нужна последняя версия из ветки разработки или производственной версии начиная с версии 3.6 или выше.
В частности, Robo 3T по-прежнему привязан к оболочке MongoDB 3.4. Таким образом, даже при подключении к работающему экземпляру MongoDB 3.6 эти опции не будут переданы на сервер из этой программы. Рекомендуется использовать только оболочку и поддерживаемые продукты, хотя есть и другие предложения, которые не имеют таких ограничений.