MongoDB: обновить подмножество массива на основе диапазона позиций - PullRequest
0 голосов
/ 26 февраля 2020

Мне нужно обновить значения в массиве во многих документах MongoDB, используя операцию массовой записи (новый массив отличается для каждого документа). Мой вопрос: есть ли способ обновить подмножество значений массива на основе диапазона позиций элемента, передав массив для замены этих значений на ?

Вот моя структура документа:

{
year: 2020,
location_id: 1,
values: [1.2 0 0 5.2 1.02 8 0 0 0 0 1.2 4]
}

Допустим, я хочу заменить все значения, кроме первого, этим новым массивом:

[1 2 5.1 2 4 0 87 1 0.2 2 9]

то есть «значения» должны стать:

[1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]

Я знаю, как полностью заменить массив:

UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values': [1.2 1 2 5.1 2 4 0 87 1 0.2 2 9]}})

Но эта первая опция требует, чтобы я сначала запросил коллекцию, чтобы получить первое значение массива. Я бы хотел этого избежать.

Я также знаю, как заменить значения одно за другим 11 отдельными командами updateone (здесь в python):

col.bulk_write([UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1': 1}}),
                UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.2': 2}}),
                .... ,
                UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.11': 9}})],
               ordered = False)

Этот второй параметр означает Я собираюсь отправлять миллионы заявлений UpdateOne ежедневно, потому что у меня есть несколько миллионов документов, которые обновляются каждый день, и массив, который нужно обновить, намного больше, чем в этом простом примере. Мне это тоже не очень нравится.

Заметьте, что связанный с этим вопрос: Может ли эта вторая опция перегрузить мой сервер или она все равно не потребляет больше ресурсов, чем первая опция? Первый вариант будет означать объемный, скажем, 300'000 операторов updateOne, каждый из которых изменяет массив длиной 365, а второй вариант будет означать 300'000 * 364 операторов updateOne, каждый из которых изменяет один элемент массива.

I хотел бы иметь возможность сделать что-то вроде:

UpdateOne({'year': 2020, 'location_id': 1}, {'$set': {'values.1-end': [1 2 5.01 2 4 0 87 1 0.2 2 9]}})

т.е. указать диапазон позиций массива, который будет заменен предоставленным массивом. До сих пор я не мог найти, как это сделать. Это приведет к массовому написанию с 300'000 операторов updateOne, каждое из которых заменяет ровно те 364 значения, которые необходимо заменить.

ПРИМЕЧАНИЕ : в этом примере он заменяет «все, кроме первого значения» ", но это также может быть" все, кроме последнего значения ". Возможно также «заменить элементы в позициях с 4 по 9 на этот массив длины 6». Я пишу свой код в python.

1 Ответ

0 голосов
/ 26 февраля 2020

Вы можете использовать конвейер агрегации и использовать его для обновления:

db.collection.updateOne(
   {'year': 2020, 'location_id': 1},
   [{
      $set: {
         values: {
            $concatArrays: [
               [{ $arrayElemAt: ["$values", 0] }],
               [1, 2, 5.1, 2, 4, 0, 87, 1, 0.2, 2, 9]
            ]
         }
      }
   }]
)

Для таких операций, как «заменить элементы в позициях 4–9 на этот массив длины 6», вы также можете использовать $ slice

Также может помочь оператор $ range , см. Как изменить значение в массиве по позиции в структуре агрегации

...