Overview
考虑这样一种情况:您想要将一个文档插入到一个集合中,更新多个其他文档,然后删除一个文档。 如果使用单独的方法,则每个操作都需要调用自己的数据库。 本指南向您展示如何使用批量写入操作在单个数据库调用中执行多个写入操作。
样本数据
本指南中的示例使用 Atlas示例数据集中的 sample_restaurants.restaurants
集合。 要学习;了解如何创建免费的MongoDB Atlas 群集并加载示例数据集,请参阅 PyMongo入门教程。
定义写入操作
对于要执行的每个写入操作,请创建以下操作类之一的实例:
InsertOne
UpdateOne
UpdateMany
ReplaceOne
DeleteOne
DeleteMany
然后,将这些实例的列表传递给bulk_write()
方法。
以下部分介绍如何创建和使用上述类的实例。
插入操作
要执行插入操作,请创建InsertOne
的实例并指定要插入的文档。
以下示例创建了一个InsertOne
实例:
operation = pymongo.InsertOne( { "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Manhattan", "restaurant_id": "1234" } )
您还可以通过将自定义类的实例传递给构造函数来创建 InsertOne
的实例。如果您使用类型检查工具,这将提供额外的类型安全性。您传递的实例必须从 TypedDict
类继承。
注意
Python 3.7 及更早版本中的 TypedDict
TypedDict 类位于typing
模块中,该模块仅在Python.3 8TypedDict
及更高版本中可用。要在早期版本的Python中使用 类,请安装typing_extensions包。
以下示例使用自定义类构造一个 InsertOne
实例,以提高类型安全性:
class Restaurant (TypedDict): name: str cuisine: str borough: str restaurant_id: str operation = pymongo.InsertOne(Restaurant( name="Mongo's Deli", cuisine="Sandwiches", borough="Manhattan", restaurant_id="1234"))
要插入多个文档,请为每个文档创建一个InsertOne
实例。
注意
_id字段必须是唯一的
在MongoDB集合中,每个文档都必须包含具有唯一值的 _id
字段。
如果为 _id
字段指定值,则必须确保该值在集合中是唯一的。如果不指定值,驾驶员会自动为该字段生成唯一的 ObjectId
值。
我们建议让驾驶员自动生成 _id
值以确保唯一性。重复的 _id
值违反了唯一索引约束,导致驾驶员返回错误。
更新操作
要更新文档,请创建UpdateOne
的实例并传入以下参数:
查询筛选器,用于指定匹配集合中文档的条件
要执行的更新操作。 有关更新操作的更多信息,请参阅MongoDB Server手册中的字段更新操作符指南。
UpdateOne
更新与查询筛选器匹配的第一个文档。
以下示例创建了一个UpdateOne
实例:
operation = pymongo.UpdateOne( { "name": "Mongo's Deli" }, { "$set": { "cuisine": "Sandwiches and Salads" }}, )
要更新多个文档,请创建UpdateMany
的实例并传入相同的参数。 UpdateMany
更新与查询过滤匹配的所有文档。
以下示例创建了一个UpdateMany
实例:
operation = pymongo.UpdateMany( { "name": "Mongo's Deli" }, { "$set": { "cuisine": "Sandwiches and Salads" }}, )
替换操作
替换操作会删除指定文档的所有字段和值,然后替换为新的字段和值。 要执行替换操作,请创建ReplaceOne
的实例,并向其传递查询筛选器以及要在匹配文档中存储的字段和值。
以下示例创建了一个ReplaceOne
实例:
operation = pymongo.ReplaceOne( { "restaurant_id": "1234" }, { "name": "Mongo's Pizza", "cuisine": "Pizza", "borough": "Brooklyn", "restaurant_id": "5678" } )
您还可以通过将自定义类的实例传递给构造函数来创建 ReplaceOne
的实例。如果您使用类型检查工具,这将提供额外的类型安全性。您传递的实例必须从 TypedDict
类继承。
注意
Python 3.7 及更早版本中的 TypedDict
TypedDict 类位于typing
模块中,该模块仅在Python.3 8TypedDict
及更高版本中可用。要在早期版本的Python中使用 类,请安装typing_extensions包。
以下示例使用自定义类构造了一个 ReplaceOne
实例,以提高类型安全性:
class Restaurant (TypedDict): name: str cuisine: str borough: str restaurant_id: str operation = pymongo.ReplaceOne( { "restaurant_id": "1234" }, Restaurant(name="Mongo's Pizza", cuisine="Pizza", borough="Brooklyn", restaurant_id="5678") )
要替换多个文档,必须为每个文档创建一个ReplaceOne
实例。
删除操作
要删除文档,请创建DeleteOne
的实例并传入查询过滤,指定要删除的文档。 DeleteOne
仅删除与查询过滤匹配的第一个文档。
以下示例创建了一个DeleteOne
实例:
operation = pymongo.DeleteOne({ "restaurant_id": "5678" })
要删除多个文档,请创建DeleteMany
的实例并传入查询过滤,指定要删除的文档。 DeleteMany
会删除与查询过滤匹配的所有文档。
以下示例创建了一个DeleteMany
实例:
operation = pymongo.DeleteMany({ "name": "Mongo's Deli" })
调用bulk_write()
方法
为要执行的每个操作定义类实例后,将这些实例的列表传递给bulk_write()
方法。 默认,该方法按照列表中定义的顺序运行操作。
以下示例使用bulk_write()
方法执行多个写入操作:
operations = [ pymongo.InsertOne( { "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Manhattan", "restaurant_id": "1234" } ), pymongo.InsertOne( { "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Brooklyn", "restaurant_id": "5678" } ), pymongo.UpdateMany( { "name": "Mongo's Deli" }, { "$set": { "cuisine": "Sandwiches and Salads" }}, ), pymongo.DeleteOne( { "restaurant_id": "1234" } ) ] results = restaurants.bulk_write(operations) print(results)
BulkWriteResult({'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 2, 'nUpserted': 0, 'nMatched': 2, 'nModified': 2, 'nRemoved': 1, 'upserted': []}, acknowledged=True)
如果任何写入操作失败,PyMongo 都会引发BulkWriteError
并且不会执行任何进一步的操作。 BulkWriteError
提供了一个details
属性,其中包括失败的操作以及有关异常的详细信息。
注意
当PyMongo运行批量操作时,它会使用运行该操作的集合的write_concern
。 无论执行顺序如何,驾驶员在尝试所有操作后都会报告所有写关注(write concern)错误。
自定义批量写入操作
bulk_write()
方法可以选择接受其他参数,这些参数表示可用于配置批量写入操作的选项。 如果不指定任何其他选项,驱动程序不会自定义批量写入操作。
属性 | 说明 |
---|---|
| If True , the driver performs the write operations in the order
provided. If an error occurs, the remaining operations are not
attempted.If False , the driver performs the operations in an
arbitrary order and attempts to perform all operations.Defaults to True . |
| Specifies whether the operation bypasses document-level validation. For more
information, see Schema
Validation in the MongoDB
Server manual. Defaults to False . |
| An instance of ClientSession . For more information, see the API
documentation. |
| A comment to attach to the operation. For more information, see the delete command
fields guide in the
MongoDB Server manual. |
| A map of parameter names and values. Values must be constant or closed
expressions that don't reference document fields. For more information,
see the let statement in the
MongoDB Server manual. |
以下示例调用上一示例中的bulk_write()
方法,并将ordered
选项设置为False
:
results = restaurants.bulk_write(operations, ordered=False)
如果无序批量写入中的任何写入操作失败, PyMongo仅在尝试所有操作后才会报告错误。
注意
无序批量操作不保证执行顺序。 为了优化运行时间,顺序可以与您列出的方式不同。
返回值
bulk_write()
方法返回一个BulkWriteResult
对象。 BulkWriteResult
对象包含以下属性:
属性 | 说明 |
---|---|
| Indicates if the server acknowledged the write operation. |
| The raw bulk API result returned by the server. |
| The number of documents deleted, if any. |
| The number of documents inserted, if any. |
| The number of documents matched for an update, if applicable. |
| The number of documents modified, if any. |
| The number of documents upserted, if any. |
| A map of the operation's index to the _id of the upserted documents, if
applicable. |
故障排除
客户端类型注解
如果没有为 MongoClient
对象添加类型注解,类型检查器可能会显示类似于以下内容的错误:
from pymongo import MongoClient client = MongoClient() # error: Need type annotation for "client"
解决方案是将 MongoClient
对象注释为 client: MongoClient
或 client: MongoClient[Dict[str, Any]]
。
不兼容类型
如果您指定 MongoClient
作为类型提示,但不包含文档、键和值的数据类型,则类型检查器可能会显示类似于以下内容的错误:
error: Dict entry 0 has incompatible type "str": "int"; expected "Mapping[str, Any]": "int"
解决方案是将以下类型提示添加到 MongoClient
对象:
client: MongoClient[Dict[str, Any]]
更多信息
要了解如何执行单个写入操作,请参阅以下指南:
API 文档
要进一步了解本指南所讨论的任何方法或类型,请参阅以下 API 文档: