Обновить записи новыми объектами
Скажем, у меня есть следующая коллекция MongoDB (я использую mongomock
для этого примера, поэтому его легко воспроизвести):
import mongomock
collection = mongomock.MongoClient().db.collection
objects = [{'name': 'Alice', 'age': 21}, {'name': 'Bob', 'age': 20}]
collection.insert_many(objects)
Затем я хотел бы обновить свои существующие объекты полями из некоторых новых объектов:
new_objects = [{'name': 'Alice', 'height': 170}, {'name': 'Caroline', 'height': 160}]
Единственный способ, которым я мог это сделать, - это:
for record in new_objects:
if collection.find_one({'name': record['name']}) is not None:
collection.update_one({'name': record['name']}, {'$set': {'height': record['height']}})
else:
collection.insert_one(record)
Однако если new_objects
очень большой, тогда этот метод становится медленным - есть ли способ использовать update_many
для этого?
1 ответ
Вы не можете использовать update_many()
, потому что для этого требуется один фильтр, который в вашем случае не будет работать, поскольку каждый фильтр отличается.
Более простая конструкция использует upsert=True
чтобы избежать логики вставки / обновления, а также устанавливает все поля, указанные в записи, которая меньше кодирует:
for record in objects + new_objects:
collection.update_one({'name': record.get('name')}, {'$set': record}, upsert=True)
Если он замедляется из-за большего количества обновлений, убедитесь, что у вас есть индекс на name
поле с использованием (в оболочке mongo):
db.collection.createIndex( { "name": 1 } )
Вы можете немного увеличить производительность, используя операцию bulk_write. Пример работы:
from pymongo import MongoClient, UpdateOne
collection = MongoClient().db.collection
objects = [{'name': 'Alice', 'age': 21}, {'name': 'Bob', 'age': 20}]
new_objects = [{'name': 'Alice', 'height': 170}, {'name': 'Caroline', 'height': 160}]
updates = []
for record in objects + new_objects:
updates.append(UpdateOne({'name': record.get('name')}, {'$set': record}, upsert=True))
collection.bulk_write(updates)
for record in collection.find({}, {'_id': 0}):
print(record)
Дает:
{'name': 'Alice', 'age': 21, 'height': 170}
{'name': 'Bob', 'age': 20}
{'name': 'Caroline', 'height': 160}