У меня есть документ Mongo, который содержит массив элементов.
Я хотел бы сбросить .handled
атрибут всех объектов в массиве, где .profile
= XX.
Документ в следующей форме:
{
"_id": ObjectId("4d2d8deff4e6c1d71fc29a07"),
"user_id": "714638ba-2e08-2168-2b99-00002f3d43c0",
"events": [{
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 10,
"data": "....."
} {
"handled": 1,
"profile": 20,
"data": "....."
}
...
]
}
Итак, я попробовал следующее:
.update({"events.profile":10},{$set:{"events.$.handled":0}},false,true)
Однако он обновляет только первый соответствующий элемент массива в каждом документе. (Это определенное поведение для $ - позиционный оператор .)
Как я могу обновить все соответствующие элементы массива?
arrays
mongodb
mongodb-query
LiorH
источник
источник
Ответы:
В данный момент невозможно использовать позиционный оператор для обновления всех элементов в массиве. См. JIRA http://jira.mongodb.org/browse/SERVER-1243
В качестве обходного пути вы можете:
источник
С выпуском MongoDB 3.6 (и доступным в ветке разработки от MongoDB 3.5.12) вы можете обновлять несколько элементов массива за один запрос.
При этом используется отфильтрованный
$[<identifier>]
синтаксис оператора позиционного обновления, представленный в этой версии:"arrayFilters"
, Переданный в качестве вариантов.update()
или даже.updateOne()
,.updateMany()
,.findOneAndUpdate()
или.bulkWrite()
метод определяет условия , чтобы соответствовать по идентификатору , указанному в заявлении обновления. Все элементы, соответствующие указанному условию, будут обновлены.Отмечая, что,
"multi"
как указано в контексте вопроса, использовалось в ожидании, что это «обновит несколько элементов», но это не так и все еще не так. Его использование здесь применяется к «нескольким документам», как это всегда было или теперь указано иным образом как обязательная настройка.updateMany()
в современных версиях API.Смотрите также,
positional all $[]
который также обновляет «несколько элементов массива», но без применения к указанным условиям и применяется ко всем элементам в массиве, где это желаемое действие.Также смотрите Обновление вложенного массива с помощью MongoDB, чтобы узнать, как эти новые позиционные операторы применяются к «вложенным» структурам массивов, где «массивы находятся в других массивах».
источник
elem
?arrayFilters
пока не поддерживает , поэтому запускайте обновление через CLI. stackoverflow.com/questions/48322834/…То, что работало для меня, было этим:
Я думаю, это понятнее для новичков Монго и всех, кто знаком с JQuery и друзьями.
источник
db.posts.find({ 'permalink':permalink }).forEach( function(doc) {...
и получаюOops.. TypeError: Object # has no method 'forEach'
db.posts.find(...).toArray().forEach(...)
Javascript
? Я хочу выполнить это обновление непосредственно из оболочки Монго без использования Javascript API.Это также может быть выполнено с помощью цикла while, который проверяет, остаются ли какие-либо документы, у которых все еще есть вложенные документы, которые не были обновлены. Этот метод сохраняет атомарность ваших обновлений (чего нет во многих других решениях).
Количество выполнений цикла будет равно максимальному числу случаев, когда поддокументы,
profile
равные 10 иhandled
не равные 0, встречаются в любом из документов в вашей коллекции. Таким образом, если в вашей коллекции 100 документов, и в одном из них есть три соответствующих вложенных документа,query
а во всех других документах меньше соответствующих вложенных документов, цикл будет выполнен три раза.Этот метод исключает опасность засорения других данных, которые могут быть обновлены другим процессом во время выполнения этого сценария. Это также сводит к минимуму объем данных, передаваемых между клиентом и сервером.
источник
На самом деле это относится к давней проблеме на http://jira.mongodb.org/browse/SERVER-1243, где на самом деле существует ряд проблем с ясным синтаксисом, который поддерживает «все случаи», когда сопоставления с множественными массивами нашел. Фактически уже существуют методы, которые «помогают» в решении этой проблемы, такие как « Массовые операции», которые были реализованы после этой первоначальной публикации.
До сих пор невозможно обновить более одного сопоставленного элемента массива в одном операторе обновления, поэтому даже при «многократном» обновлении все, что вы когда-либо сможете обновить, - это только один согласованный элемент в массиве для каждого документа в этом отдельном документе. заявление.
Наилучшее возможное решение в настоящее время - это найти и зациклить все соответствующие документы и обработать массовые обновления, которые по крайней мере позволят отправлять много операций в одном запросе с единичным ответом. При желании вы можете использовать
.aggregate()
для уменьшения содержимого массива, возвращаемого в результате поиска, до тех, которые соответствуют условиям для выбора обновления:.aggregate()
Часть будет работать , когда есть «уникальный» идентификатор для массива или всего содержимого для каждого элемента образует «уникальный» элемент сам. Это связано с тем, что оператор «set»$setDifference
используется для фильтрации любыхfalse
значений, возвращаемых$map
операцией, используемой для обработки массива на совпадения.Если содержимое вашего массива не имеет уникальных элементов, вы можете попробовать альтернативный подход с
$redact
:Ограничение состоит в том, что если «обработано» на самом деле поле, предназначенное для присутствия на других уровнях документа, то вы, вероятно, получите неожиданные результаты, но это хорошо, если это поле появляется только в одной позиции документа и является совпадением равенства.
Будущие выпуски (после 3.1 MongoDB) на момент написания будут иметь более
$filter
простую операцию:И все выпуски, которые поддерживают,
.aggregate()
могут использовать следующий подход$unwind
, но использование этого оператора делает его наименее эффективным подходом из-за расширения массива в конвейере:Во всех случаях, когда версия MongoDB поддерживает «курсор» из совокупного вывода, тогда это просто вопрос выбора подхода и повторения результатов с тем же блоком кода, который показан для обработки операторов массового обновления. Массовые операции и «курсоры» из совокупного вывода представлены в одной и той же версии (MongoDB 2.6) и поэтому обычно работают рука об руку для обработки.
В более ранних версиях, вероятно, лучше всего просто использовать
.find()
для возврата курсора и отфильтровывать выполнение операторов по количеству совпадений элемента массива для.update()
итераций:Если вы абсолютно решительно настроены на «множественные» обновления или считаете, что в конечном итоге это более эффективно, чем обработка нескольких обновлений для каждого сопоставленного документа, тогда вы всегда можете определить максимальное количество возможных совпадений с массивами и просто выполнить «многократное» обновление, которое много раз, пока в основном нет больше документов для обновления.
Действительный подход для версий MongoDB 2.4 и 2.2 также можно использовать
.aggregate()
для поиска этого значения:В любом случае, есть некоторые вещи, которые вы не хотите делать в обновлении:
Не обновляйте массив «одним выстрелом»: если, по вашему мнению, может быть более эффективно обновить весь контент массива в коде, а затем только
$set
весь массив в каждом документе. Это может показаться быстрее для обработки, но нет никакой гарантии, что содержимое массива не изменилось с момента его чтения и выполнения обновления. Хотя$set
он все еще является атомарным оператором, он будет обновлять массив только тем, что, по его мнению, является правильными данными, и, таким образом, может перезаписывать любые изменения, происходящие между чтением и записью.Не рассчитывайте значения индекса для обновления: если вы похожи на подход «одним выстрелом», вы просто определяете, что позиция
0
и позиция2
(и т. Д.) Являются элементами для обновления и кодирования их с помощью и конечного выражения, например:Опять проблема здесь заключается в «предположении», что эти значения индекса, найденные при чтении документа, являются одинаковыми значениями индекса в массиве во время обновления. Если новые элементы добавляются в массив таким образом, что это меняет порядок, то эти позиции больше не действительны, а неправильные элементы фактически обновляются.
Таким образом, до тех пор, пока не будет определен разумный синтаксис, позволяющий обрабатывать несколько совпадающих элементов массива в одном операторе обновления, тогда основной подход состоит в том, чтобы либо обновлять каждый совпадающий элемент массива в отдельном операторе (в идеале, в массе), либо по существу вырабатывать максимальное количество элементов массива. обновлять или продолжать обновлять до тех пор, пока больше не будут изменены результаты. В любом случае, вы должны «всегда» обрабатывать позиционные
$
обновления для элемента соответствующего массива, даже если это обновляет только один элемент на оператор.Массовые операции на самом деле являются «обобщенным» решением для обработки любых операций, которые работают как «множественные операции», и, поскольку для этого существует больше приложений, чем просто обновление нескольких элементов массива с тем же значением, то, конечно, оно было реализовано уже, и в настоящее время это лучший подход для решения этой проблемы.
источник
Я поражен, что это все еще не было обращено в Монго. В целом, монго выглядит не очень хорошо при работе с подмассивами. Вы не можете сосчитать подмассивы просто, например.
Я использовал первое решение Хавьера. Считайте массив в события, затем выполните цикл и создайте набор exp:
Это можно абстрагировать в функцию с помощью обратного вызова для условного теста
источник
Я искал решение этой проблемы, используя новейший драйвер для C # 3.6, и вот исправление, на котором я в конце концов остановился. Ключ здесь использует "$ []", который согласно MongoDB является новым с версии 3.6. См. Https://docs.mongodb.com/manual/reference/operator/update/positional-all/#up. S [] для получения дополнительной информации.
Вот код:
Для получения дополнительной информации см. Мой оригинальный пост здесь: Удалите элемент массива из ВСЕХ документов с помощью драйвера MongoDB C #
источник
Тема очень старая, но я пришел сюда, чтобы найти ответ, и поэтому нашел новое решение.
С MongoDB версии 3.6+ теперь можно использовать позиционный оператор для обновления всех элементов в массиве. Смотрите официальную документацию здесь .
Следующий запрос будет работать на вопрос, заданный здесь. Я также проверил с драйвером Java-MongoDB, и он успешно работает.
Надеюсь, это поможет кому-то вроде меня.
источник
Я попробовал следующее и все работает нормально.
// функция обратного вызова в случае nodejs
источник
Вы можете обновить все элементы в MongoDB
Это обновит все значения «status» до «complete» в массиве «arr»
Если только один документ
Но если не один, а также вы не хотите, чтобы все документы в массиве обновлялись, тогда вам нужно перебрать элемент и внутри блока if
источник
На самом деле, команда сохранения есть только в экземпляре класса Document. Это имеет много методов и атрибутов. Таким образом, вы можете использовать функцию lean (), чтобы уменьшить рабочую нагрузку. Обратитесь сюда. https://hashnode.com/post/why-are-mongoose-mongodb-odm-lean-queries-faster-than-normal-queries-cillvawhq0062kj53asxoyn7j
Еще одна проблема с функцией сохранения, которая одновременно создает конфликт данных с мульти-сохранением. Model.Update будет делать данные последовательно. Таким образом, чтобы обновить несколько элементов в массиве документа. Используйте свой знакомый язык программирования и попробуйте что-то вроде этого, я использую мангуст в этом:
источник
Оператор $ [] выбирает весь вложенный массив. Вы можете обновить все элементы массива с помощью $ []
Ссылка
источник
$[]
просто обновляет все поля в указанном массиве. Работает фильтрованный позиционный оператор,$[identifier]
который работает с полями массива, соответствующими указанным условиям. Следует использовать сarrayFilters
Refrence: docs.mongodb.com/manual/release-notes/3.6/#arrayfilters и docs.mongodb.com/manual/reference/operator/update/…Помните, что некоторые ответы в этой теме, предлагающие использовать $ [], НЕПРАВИЛЬНЫ.
Приведенный выше код обновит «handled» до 0 для всех элементов в массиве «events», независимо от его значения «profile». Запрос
{"events.profile":10}
предназначен только для фильтрации всего документа, а не документов в массиве. В этой ситуации необходимо использовать$[elem]
с,arrayFilters
чтобы указать условие элементов массива, чтобы ответ Нила Ланна был правильным.источник
Обновление поля массива в нескольких документах в mongo db.
Используйте $ pull или $ push с запросом update many для обновления элементов массива в mongoDb.
источник
Во-первых: ваш код не работал, потому что вы использовали позиционный оператор,
$
который только идентифицирует элемент для обновления в массиве, но даже не указывает явно его позицию в массиве.Вам нужен отфильтрованный позиционный оператор
$[<identifier>]
. Это обновит все элементы, которые соответствуют условию фильтра массива.Решение:
Посетите mongodb doc здесь
Что делает код:
{"events.profile":10}
фильтрует вашу коллекцию и возвращает документы, соответствующие фильтруОператор
$set
обновления: изменяет соответствующие поля документов, на которые он действует.{multi:true}
Это делает.update()
изменяет все документы, соответствующие фильтру, следовательно, ведет себя какupdateMany()
{ "events.$[elem].handled" : 0 } and arrayFilters: [ { "elem.profile": 10 } ]
Этот метод предполагает использование отфильтрованного позиционного массива с arrayFilters. отфильтрованный позиционный массив здесь$[elem]
действует как заполнитель для всех элементов в полях массива, которые соответствуют условиям, указанным в фильтре массива.Фильтры массива
источник