Как обновить много значений в mongodb по списку идентификаторов? - PullRequest
0 голосов
/ 04 августа 2020

Я использую pymon go для работы с mongodb. Проблема в том, что мне нужно обновить множество записей коллекции в mongodb по списку идентификаторов.

Существует коллекция abcd со следующей структурой:

{'id': 'someid1', 'order': 0}
{'id': 'someid2', 'order': 0}
...
{'id': 'someidN', 'order': 0}

Мне нужно изменить поля order на значения, собранные в dict mapping.

mapping = {'someid1': 5, 'someid2': 7, ..., 'someidN': 50}

Самый очевидный способ (может быть неверным, так как это заняло много времени, и я прервал процесс):

for key, value in mapping.items():
    db.abcd.update_one({'id': key}, {'order': {'$set': value}})

Но как я вижу, это очень трудоемко. Есть ли какой-нибудь умный способ установить значения по списку значений? Что-то вроде этого (следующий код глуп и работает не так, как я ожидал):

db.abcd.update_many({'id': list(mapping.keys())}, {'order': {'$set': list(mapping.values())})

Я читал документы mongodb, но нашел только примеры с «условием» (например, изменить поле с тем же значением, если условие правда). Я предполагаю, что есть эффективный способ «сопоставить» значения сразу нескольким идентификаторам. Я новичок в mongodb (и pymon go), поэтому вопрос, вероятно, довольно глупый. Спасибо.

1 Ответ

1 голос
/ 04 августа 2020

Есть ли какой-нибудь умный способ установить значения по списку значений?

Используя стандартные операторы обновления, к сожалению, нет. Mongodb работает, требуя фильтра для обновления, поэтому все, что вы пытаетесь сделать, невозможно в одном update_many().

Убедитесь, что у вас есть индекс в поле id в вашем примере. Поле _id всегда индексируется (и всегда уникально), вы можете использовать его вместо этого.

С учетом сказанного, ваша простая операция не должна быть слишком медленной, если только у вас нет медленной машины / сети или очень большой набор данных. (хотя ваш код не должен был работать - ваш оператор $set был в неправильном месте)

Один из способов ускорить процесс - использовать операции массовой записи . В приведенном ниже коде показано, как это можно сделать.

from pymongo import MongoClient, UpdateOne
import pprint

db = MongoClient()['mydatabase']

# Test Data setup

for i in range(3):
    db.abcd.insert_one({'id': f'someid{i}', 'order': 0})

mapping = {'someid1': 5, 'someid2': 7}

updates = []

for key, value in mapping.items():
    updates.append(UpdateOne({'id': key}, {'$set': {'order': value}}))

# print the results

db.abcd.bulk_write(updates)

pprint.pprint(list(db.abcd.find({}, {'_id': 0})))

возвращает:

[{'id': 'someid0', 'order': 0},
 {'id': 'someid1', 'order': 5},
 {'id': 'someid2', 'order': 7}]
...