Overview
En esta guía, aprenderá a usar PyMongo para realizar operaciones masivas. Estas operaciones reducen el número de llamadas al servidor al realizar múltiples operaciones de escritura en un solo método.
El Collection Las clases MongoClient y bulk_write() proporcionan un método bulk_write(). Al llamar a en una instancia Collection, se pueden realizar múltiples operaciones de escritura en una sola colección. Al llamar a bulk_write() en una instancia MongoClient, se pueden realizar escrituras masivas en múltiples espacios de nombres. En MongoDB, un espacio de nombres consta del nombre de la base de datos y el nombre de la colección en el formato <database>.<collection>.
Importante
Para realizar operaciones masivas en una instancia MongoClient, asegúrese de que su aplicación cumpla con los siguientes requisitos:
Utiliza PyMongo v4.9 o posterior
Se conecta a MongoDB Server v8.0 o posterior
Datos de muestra
Los ejemplos de esta guía utilizan las colecciones sample_restaurants.restaurants y sample_mflix.movies de la Conjuntos de datos de muestra de Atlas. Para aprender a crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de muestra, consulte Tutorial paraempezar a usar PyMongo.
Definir las operaciones de escritura
Para cada operación de escritura que desee realizar, cree una instancia de una de las siguientes clases de operación:
InsertOneUpdateOneUpdateManyReplaceOneDeleteOneDeleteMany
Luego, pase una lista de estas instancias al método bulk_write().
Importante
Asegúrese de importar las clases de operación de escritura en su archivo de aplicación, como se muestra en el siguiente código:
from pymongo import InsertOne, UpdateOne, UpdateMany, ReplaceOne, DeleteOne, DeleteMany
Las siguientes secciones muestran cómo crear instancias de las clases anteriores, que puede utilizar para realizar operaciones de recopilación y de cliente en masa.
Operaciones de inserción
Para realizar una operación de inserción, cree una instancia de InsertOne y especifique el documento que desea insertar. Pase los siguientes argumentos de palabra clave al constructor InsertOne:
namespace: El espacio de nombres donde se insertará el documento. Este argumento es opcional si se realiza la operación masiva en una sola colección.document:El documento a insertar.
El siguiente ejemplo crea una instancia de InsertOne:
operation = InsertOne( namespace="sample_restaurants.restaurants", document={ "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Manhattan", "restaurant_id": "1234" } )
También puedes crear una instancia de InsertOne pasando una instancia de una clase personalizada al constructor. Esto proporciona mayor seguridad de tipos si usas una herramienta de verificación de tipos. La instancia que pases debe heredar de la clase TypedDict.
Nota
TypedDict en Python 3.7 y versiones anteriores
La clase TypedDict se encuentra en el módulo typing, el cual está disponible solo en Python 3.8 y versiones posteriores. Para usar la clase TypedDict en versiones anteriores de Python, instala el paquete typing_extensions.
El siguiente ejemplo construye una instancia InsertOne utilizando una clase personalizada para mayor seguridad de tipo:
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"))
Para insertar varios documentos, cree una instancia de InsertOne para cada documento.
Nota
El campo _id debe ser único
En una colección de MongoDB, cada documento debe contener un campo _id con un valor único.
Si se especifica un valor para el campo _id, debe asegurarse de que el valor sea único en la colección. De lo contrario, el controlador genera automáticamente un valor ObjectId único para el campo.
Recomendamos dejar que el controlador genere valores de _id automáticamente para garantizar la unicidad. Los valores duplicados de _id violan restricciones de índice único, lo que provoca que el controlador devuelva un error.
Operaciones de actualizar
Para actualizar un documento, cree una instancia de UpdateOne y pase los siguientes argumentos:
namespace: El espacio de nombres donde se realizará la actualización. Este argumento es opcional si se realiza la operación masiva en una sola colección.filter:El filtro de consulta que especifica los criterios utilizados para buscar coincidencias en los documentos de su colección.update: La actualización que desea realizar. Para obtener más información sobre las operaciones de actualización, consulte la guía Operadores de actualización de campos en el manual del MongoDB Server.
UpdateOne actualiza el primer documento que coincide con su filtro de consulta.
El siguiente ejemplo crea una instancia de UpdateOne:
operation = UpdateOne( namespace="sample_restaurants.restaurants", filter={ "name": "Mongo's Deli" }, update={ "$set": { "cuisine": "Sandwiches and Salads" }} )
Para actualizar varios documentos, cree una instancia de UpdateMany y pase los mismos argumentos. UpdateMany actualiza todos los documentos que coinciden con su filtro de consulta.
El siguiente ejemplo crea una instancia de UpdateMany:
operation = UpdateMany( namespace="sample_restaurants.restaurants", filter={ "name": "Mongo's Deli" }, update={ "$set": { "cuisine": "Sandwiches and Salads" }} )
Reemplazar operaciones
Una operación de reemplazo elimina todos los campos y valores de un documento específico y los reemplaza por otros nuevos. Para realizar una operación de reemplazo, cree una instancia de ReplaceOne y pase los siguientes argumentos:
namespace: El espacio de nombres donde se realizará la operación de reemplazo. Este argumento es opcional si se realiza la operación masiva en una sola colección.filter:El filtro de consulta que especifica los criterios utilizados para encontrar el documento a reemplazar.replacement:El documento que incluye los nuevos campos y valores que desea almacenar en el documento correspondiente.
El siguiente ejemplo crea una instancia de ReplaceOne:
operation = ReplaceOne( namespace="sample_restaurants.restaurants", filter={ "restaurant_id": "1234" }, replacement={ "name": "Mongo's Pizza", "cuisine": "Pizza", "borough": "Brooklyn", "restaurant_id": "5678" } )
También puedes crear una instancia de ReplaceOne pasando una instancia de una clase personalizada al constructor. Esto proporciona mayor seguridad de tipos si usas una herramienta de verificación de tipos. La instancia que pases debe heredar de la clase TypedDict.
Nota
TypedDict en Python 3.7 y versiones anteriores
La clase TypedDict se encuentra en el módulo typing, el cual está disponible solo en Python 3.8 y versiones posteriores. Para usar la clase TypedDict en versiones anteriores de Python, instala el paquete typing_extensions.
El siguiente ejemplo construye una instancia ReplaceOne utilizando una clase personalizada para mayor seguridad de tipo:
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") )
Para reemplazar varios documentos, debe crear una instancia de ReplaceOne para cada documento.
Tip
Herramientas de verificación de tipos
Para aprender más sobre las herramientas de verificación de tipos disponibles para Python, échale un vistazo a Verificadores de tipos en la página de herramientas.
Operaciones de borrar
Para eliminar un documento, cree una instancia de DeleteOne y pase los siguientes argumentos:
namespace: El espacio de nombres donde se eliminará el documento. Este argumento es opcional si se realiza la operación masiva en una sola colección.filter:El filtro de consulta que especifica los criterios utilizados para encontrar el documento que se va a eliminar.
DeleteOne elimina sólo el primer documento que coincide con su filtro de consulta.
El siguiente ejemplo crea una instancia de DeleteOne:
operation = DeleteOne( namespace="sample_restaurants.restaurants", filter={ "restaurant_id": "5678" } )
Para eliminar varios documentos, cree una instancia de DeleteMany y pase un espacio de nombres y un filtro de consulta que especifique el documento que desea eliminar. DeleteMany elimina todos los documentos que coinciden con su filtro de consulta.
El siguiente ejemplo crea una instancia de DeleteMany:
operation = DeleteMany( namespace="sample_restaurants.restaurants", filter={ "name": "Mongo's Deli" } )
Llamar al método bulk_write()
Después de definir una instancia de clase para cada operación que desee realizar, pase una lista de estas instancias al método bulk_write(). Llame al método bulk_write() en una instancia Collection para escribir en una sola colección o en una instancia MongoClient para escribir en varios espacios de nombres.
Si alguna de las operaciones de escritura llamadas en un Collection falla, PyMongo genera un BulkWriteError y no realiza ninguna operación adicional. BulkWriteError proporciona un atributo details que incluye la operación que falló y detalles sobre la excepción.
Si alguna de las operaciones de escritura llamadas en un MongoClient falla, PyMongo genera un ClientBulkWriteException y no realiza ninguna operación adicional. ClientBulkWriteException proporciona un atributo error que incluye información sobre la excepción.
Nota
Cuando PyMongo ejecuta una operación masiva, utiliza el write_concern de la colección o cliente donde se ejecuta la operación. También puede configurar una preocupación de escritura para la operación al usar el método MongoClient.bulk_write(). El controlador informa todos los errores de preocupación de escritura después de intentar todas las operaciones, independientemente del orden de ejecución.
Para obtener más información sobre las preocupaciones de escritura, consulte Preocupación de escritura en el manual de MongoDB Server.
Ejemplo de escritura masiva de colección
El siguiente ejemplo realiza múltiples operaciones de escritura en la colección restaurants utilizando el método bulk_write() en una instancia Collection. Seleccione el Synchronous o pestaña Asynchronous para ver el código correspondiente:
operations = [ InsertOne( document={ "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Manhattan", "restaurant_id": "1234" } ), InsertOne( document={ "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Brooklyn", "restaurant_id": "5678" } ), UpdateMany( filter={ "name": "Mongo's Deli" }, update={ "$set": { "cuisine": "Sandwiches and Salads" }} ), DeleteOne( filter={ "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)
operations = [ InsertOne( document={ "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Manhattan", "restaurant_id": "1234" } ), InsertOne( document={ "name": "Mongo's Deli", "cuisine": "Sandwiches", "borough": "Brooklyn", "restaurant_id": "5678" } ), UpdateMany( filter={ "name": "Mongo's Deli" }, update={ "$set": { "cuisine": "Sandwiches and Salads" }} ), DeleteOne( filter={ "restaurant_id": "1234" } ) ] results = await restaurants.bulk_write(operations) print(results)
BulkWriteResult({'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 2, 'nUpserted': 0, 'nMatched': 2, 'nModified': 2, 'nRemoved': 1, 'upserted': []}, acknowledged=True)
Ejemplo de escritura masiva de clientes
El siguiente ejemplo realiza varias operaciones de escritura en los espacios de nombres sample_restaurants.restaurants y sample_mflix.movies mediante el método bulk_write() en una instancia MongoClient. Seleccione la pestaña Synchronous o Asynchronous para ver el código correspondiente:
operations = [ InsertOne( namespace="sample_mflix.movies", document={ "title": "Minari", "runtime": 217, "genres": ["Drama", "Comedy"] } ), UpdateOne( namespace="sample_mflix.movies", filter={ "title": "Minari" }, update={ "$set": { "runtime": 117 }} ), DeleteMany( namespace="sample_restaurants.restaurants", filter={ "cuisine": "French" } ) ] results = client.bulk_write(operations) print(results)
ClientBulkWriteResult({'anySuccessful': True, 'error': None, 'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 1, 'nUpserted': 0, 'nMatched': 1, 'nModified': 1, 'nDeleted': 344, 'insertResults': {}, 'updateResults': {}, 'deleteResults': {}}, acknowledged=True, verbose=False)
operations = [ InsertOne( namespace="sample_mflix.movies", document={ "title": "Minari", "runtime": 217, "genres": ["Drama", "Comedy"] } ), UpdateOne( namespace="sample_mflix.movies", filter={ "title": "Minari" }, update={ "$set": { "runtime": 117 }} ), DeleteMany( namespace="sample_restaurants.restaurants", filter={ "cuisine": "French" } ) ] results = await client.bulk_write(operations) print(results)
ClientBulkWriteResult({'anySuccessful': True, 'error': None, 'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 1, 'nUpserted': 0, 'nMatched': 1, 'nModified': 1, 'nDeleted': 344, 'insertResults': {}, 'updateResults': {}, 'deleteResults': {}}, acknowledged=True, verbose=False)
Personalizar operaciones de escritura masiva
El método bulk_write() acepta opcionalmente parámetros adicionales, que representan opciones que puede utilizar para configurar la operación de escritura masiva.
Opciones de escritura masiva de colecciones
La siguiente tabla describe las opciones que puede pasar al método Collection.bulk_write():
Propiedad | Descripción |
|---|---|
| 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. |
El siguiente ejemplo llama al bulk_write() método del ejemplo anterior de escritura masiva de colección, pero establece la ordered opción False en. Seleccione Synchronous Asynchronous la pestaña o para ver el código correspondiente:
results = restaurants.bulk_write(operations, ordered=False)
results = await restaurants.bulk_write(operations, ordered=False)
Si alguna de las operaciones de escritura en una escritura masiva desordenada falla, PyMongo informa los errores solo después de intentar todas las operaciones.
Nota
Las operaciones masivas desordenadas no garantizan el orden de ejecución. El orden puede variar según la forma en que se enumeran para optimizar el tiempo de ejecución.
Opciones de escritura masiva del cliente
La siguiente tabla describe las opciones que puede pasar al método MongoClient.bulk_write():
Propiedad | Descripción |
|---|---|
| An instance of ClientSession. For more information, see the API
documentation. |
| 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 returns detailed results for each
successful operation. Defaults to False. |
| Specifies whether the operation bypasses document-level validation. For more
information, see Schema
Validation in the MongoDB
Server manual. Defaults to False. |
| 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. |
| Specifies the write concern to use for the bulk operation.
For more information, see Write Concern
in the MongoDB Server manual. |
El siguiente ejemplo llama al bulk_write() método del ejemplo anterior de escritura masiva de cliente, pero establece la verbose_results opción True en. Seleccione la Synchronous Asynchronous pestaña o para ver el código correspondiente:
results = client.bulk_write(operations, verbose_results=True)
ClientBulkWriteResult({'anySuccessful': True, 'error': None, 'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 1, 'nUpserted': 0, 'nMatched': 1, 'nModified': 1, 'nDeleted': 344, 'insertResults': {0: InsertOneResult(ObjectId('...'), acknowledged=True)}, 'updateResults': {1: UpdateResult({'ok': 1.0, 'idx': 1, 'n': 1, 'nModified': 1}, acknowledged=True)}, 'deleteResults': {2: DeleteResult({'ok': 1.0, 'idx': 2, 'n': 344}, acknowledged=True)}}, acknowledged=True, verbose=True)
results = await client.bulk_write(operations, verbose_results=True)
ClientBulkWriteResult({'anySuccessful': True, 'error': None, 'writeErrors': [], 'writeConcernErrors': [], 'nInserted': 1, 'nUpserted': 0, 'nMatched': 1, 'nModified': 1, 'nDeleted': 344, 'insertResults': {0: InsertOneResult(ObjectId('...'), acknowledged=True)}, 'updateResults': {1: UpdateResult({'ok': 1.0, 'idx': 1, 'n': 1, 'nModified': 1}, acknowledged=True)}, 'deleteResults': {2: DeleteResult({'ok': 1.0, 'idx': 2, 'n': 344}, acknowledged=True)}}, acknowledged=True, verbose=True)
Return Values
Esta sección describe el valor de retorno de los siguientes métodos de operación masiva:
Valor de retorno de escritura masiva de colección
El método Collection.bulk_write() devuelve un objeto BulkWriteResult. El objeto BulkWriteResult contiene las siguientes propiedades:
Propiedad | Descripción |
|---|---|
| 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. |
Valor de retorno de escritura masiva del cliente
El método MongoClient.bulk_write() devuelve un objeto ClientBulkWriteResult. El objeto ClientBulkWriteResult contiene las siguientes propiedades:
Propiedad | Descripción |
|---|---|
| Indicates if the server acknowledged the write operation. |
| The raw bulk API result returned by the server. |
| A map of any successful delete operations and their results. |
| The number of documents deleted, if any. |
| Indicates whether the returned results are verbose. |
| A map of any successful insert operations and their results. |
| The number of documents inserted, if any. |
| The number of documents matched for an update, if applicable. |
| The number of documents modified, if any. |
| A map of any successful update operations and their results. |
| The number of documents upserted, if any. |
Solución de problemas
Anotaciones de tipo de cliente
Si no se agrega una anotación de tipo para el objeto MongoClient, el verificador de tipos podría mostrar un error similar al siguiente:
from pymongo import MongoClient client = MongoClient() # error: Need type annotation for "client"
La solución es anotar el objeto MongoClient como client: MongoClient o client: MongoClient[Dict[str, Any]].
Tipo incompatible
Si especifica MongoClient como una sugerencia de tipo, pero no incluye los tipos de datos para el documento, las claves y los valores, su verificador de tipos podría mostrar un error similar al siguiente:
error: Dict entry 0 has incompatible type "str": "int"; expected "Mapping[str, Any]": "int"
La solución es agregar la siguiente sugerencia de tipo al objeto MongoClient:
client: MongoClient[Dict[str, Any]]
Información Adicional
Para aprender a realizar operaciones de escritura individuales, consulte las siguientes guías:
Documentación de la API
Para obtener más información sobre cualquiera de los métodos o tipos discutidos en esta guía, consultar la siguiente documentación de la API: