0

假设我有以下 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它?

4

1 回答 1

1

您不能使用update_many(),因为它需要一个过滤器,在您的用例中它不起作用,因为每个过滤器都不同。

一个更简单的构造用于upsert=True避免插入/更新逻辑,并且还设置了记录中指定的所有字段,编码更少:

for record in objects + new_objects:
    collection.update_one({'name': record.get('name')}, {'$set': record}, upsert=True)

如果它因大量更新而变慢,请确保name使用(在 mongo shell 中)在字段上有一个索引:

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}
于 2020-07-24T14:04:07.303 回答