Overview
En esta guía, puedes aprender a utilizar PyMongo para realizar operaciones masivas. Las operaciones de actualización masiva reducen el número de llamadas al servidor realizando múltiples operaciones de guardar en un solo método.
La Collection y las clases MongoClient ambas proporcionan un método bulk_write(). Al llamar a bulk_write() en una instancia de Collection, puedes realizar múltiples operaciones de guardar en una sola colección. Al llamar a bulk_write() en una instancia MongoClient, puedes realizar escrituras en bloque en varios nombres de namespaces. En MongoDB, un namespace consiste en el 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 de 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 Comenzar con PyMongo tutorial.
Defina las operaciones de guardado
Para cada operación de guardar que desees realizar, crea una instancia de una de las siguientes clases de operaciones:
InsertOneUpdateOneUpdateManyReplaceOneDeleteOneDeleteMany
Luego, pasa una lista de estas instancias al método bulk_write().
Importante
Asegúrese de importar las clases de operaciones de escritura a 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 previas, que puedes utilizar para realizar operaciones masivas de colección y cliente.
Operaciones de inserción
Para realizar una operación de inserción, crea una instancia de InsertOne y especifica el documento que deseas insertar. Pasa los siguientes argumentos clave al constructor InsertOne:
namespace: El namespace en el que insertar el documento. Este argumento es opcional si 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 de 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 query que especifica los criterios usados para emparejar documentos en tu 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 el filtro de query.
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, crea una instancia de UpdateMany y pasa los mismos argumentos. UpdateMany actualiza todos los documentos que coincidan con su filtro de query.
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 remueve todos los campos y valores de un documento especificado y los reemplaza por otros nuevos. Para realizar una operación de reemplazo, crea una instancia de ReplaceOne y pasa los siguientes argumentos:
namespace: El espacio de nombres en el que llevar a cabo la operación de reemplazo. Este argumento es opcional si realiza la operación masiva en una sola colección.filter: El filtro de query que especifica los criterios utilizados para emparejar el documento a reemplazar.replacement: El documento que incluye los nuevos campos y valores que desea almacenar en el documento coincidente.
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 de ReplaceOne usando 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 query que especifica los criterios utilizados para hacer coincidir el documento a eliminar.
DeleteOne elimina únicamente el primer documento que coincida con tu filtro de query.
El siguiente ejemplo crea una instancia de DeleteOne:
operation = DeleteOne( namespace="sample_restaurants.restaurants", filter={ "restaurant_id": "5678" } )
Para borrar varios documentos, crea una instancia de DeleteMany e introduce un namespace y un filtro de query que especifique el documento que deseas borrar. DeleteMany remueve todos los documentos que coinciden con tu filtro de query.
El siguiente ejemplo crea una instancia de DeleteMany:
operation = DeleteMany( namespace="sample_restaurants.restaurants", filter={ "name": "Mongo's Deli" } )
Llama 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 guardar 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 guardar activadas en una MongoClient falla, PyMongo arroja un ClientBulkWriteException y no realiza más operaciones. 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 en el que se ejecuta la operación. También puedes establecer un nivel de confirmación de escritura (write concern) para la operación cuando uses el método MongoClient.bulk_write(). El driver informa de todos los errores de nivel de confirmación de escritura (write concern) después de intentar todas las operaciones, independientemente del orden de ejecución.
Para obtener más información sobre nivel de confirmación de escritura (write concern), consulta nivel de confirmación de escritura (write concern) en el manual del servidor de MongoDB.
Ejemplo De Guardar Masiva En 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 de Collection. Elija el Synchronous o la 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 del cliente
El siguiente ejemplo realiza múltiples operaciones de escritura en los espacios de nombres sample_restaurants.restaurants y sample_mflix.movies utilizando el método bulk_write() en una instancia de MongoClient. Selecciona 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)
Personaliza las 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 puedes 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 método bulk_write() del anterior Ejemplo de guardar masivo en la colección, pero establece la opción ordered en False. Selecciona la pestaña Synchronous o Asynchronous 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 guardar en una escritura masiva no ordenada falla, PyMongo informa los errores solo después de intentar todas las operaciones.
Nota
Las operaciones masivas no ordenadas no ofrecen garantías del orden de ejecución. El orden puede diferir de la manera en que los enumeras para optimizar el tiempo de ejecución.
Opciones de escritura masiva de clientes
La siguiente tabla describe las opciones que puedes 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 método bulk_write() desde el anterior Ejemplo de escritura masiva en el cliente, pero configura la opción verbose_results en True. Selecciona la pestaña Synchronous o Asynchronous 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 guardar masivo 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 cómo realizar operaciones de guardar individuales, consulta los 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: