Overview
En esta guía, puedes aprender a realizar múltiples operaciones de escritura en una sola llamada a la base de datos utilizando operaciones de escritura en bloque.
Considera un escenario en el que quieres insertar un documento, actualizar varios otros documentos y luego borrar un documento. Si utiliza métodos individuales, cada operación requiere su propia llamada a la base de datos.
Al utilizar una operación de guardar masiva, puedes realizar múltiples operaciones de guardar en menos llamadas a la base de datos. Puedes realizar operaciones de guardar en bloque en los siguientes niveles:
Colección: puedes usar la
MongoCollection.bulkWrite()Método para realizar operaciones de escritura masiva en una sola colección. Con este método, cada tipo de operación de escritura requiere al menos una llamada a la base de datos. Por ejemplo,MongoCollection.bulkWrite()realiza múltiples operaciones de actualización en una sola llamada, pero realiza dos llamadas separadas a la base de datos para una operación de inserción y una operación de reemplazo.Cliente: Si tu aplicación se conecta a MongoDB Server versión 8.0 o posterior, puedes usar el método
MongoClient.bulkWrite()para realizar operaciones de escritura masiva en múltiples colecciones y bases de datos dentro del mismo clúster. Este método realiza todas las operaciones de guardar en una sola llamada a la base de datos.
Datos de muestra
Los ejemplos en esta guía utilizan la colección sample_restaurants.restaurants de los 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, consulta el
Comenzar tutorial.
Importante
Proyecto Reactor librería
Esta guía usa la librería Proyecto Reactor para consumir instancias Publisher devueltas por los métodos del driver Reactive Streams de Java. Para obtener más información sobre la biblioteca Project Reactor y cómo utilizarla, consulta Primeros pasos en la documentación de Reactor. Para obtener más información sobre cómo utilizamos los métodos de la librería Project Reactor en esta guía, consulta la guía Guardar datos en MongoDB.
Guardar masivo de colecciones
Las operaciones de escritura en bloque contienen una o más operaciones de escritura. Para realizar una operación de guardar masiva a nivel de colección, pasa un List de WriteModel documentos al método MongoCollection.bulkWrite(). Un WriteModel es un modelo que representa una operación de escritura.
Para cada operación de guardar que quieras realizar, crea una instancia de una de las siguientes clases que heredan de WriteModel:
InsertOneModelUpdateOneModelUpdateManyModelReplaceOneModelDeleteOneModelDeleteManyModel
Las siguientes secciones muestran cómo crear y utilizar instancias de las clases precedentes.
Operaciones de inserción
Para realizar una operación de inserción, crea una instancia de InsertOneModel y pasa el documento que deseas insertar.
El siguiente ejemplo crea una instancia de InsertOneModel:
InsertOneModel<Document> operation = new InsertOneModel<>( new Document("name", "Mongo's Deli") .append("cuisine", "Sandwiches"));
Para insertar varios documentos, cree una instancia de InsertOneModel para cada documento.
Operaciones de actualizar
Para actualizar un documento, crea una instancia de UpdateOneModel y pasa los siguientes argumentos:
Filtro de query que especifica los criterios utilizados para emparejar documentos en su colección.
Operación de actualización que deseas realizar. Para obtener más información sobre las operaciones de actualización, consulta la guía Operadores de actualización de campo en el Manual del Servidor MongoDB.
El siguiente ejemplo crea una instancia de UpdateOneModel:
UpdateOneModel<Document> operation = new UpdateOneModel<>( eq("name", "Mongo's Deli"), set("cuisine", "Sandwiches and Salads"));
Si varios documentos coinciden con el filtro de query especificado en la instancia UpdateOneModel, la operación actualiza el primer resultado. Puedes especificar un ordenamiento en una instancia UpdateOptions para aplicar un orden a los documentos coincidentes antes de que el servidor realice la operación de actualización, como se muestra en el siguiente código:
UpdateOptions options = UpdateOptions.sort(Sorts.ascending("_id"));
Para actualizar varios documentos, crea una instancia de UpdateManyModel y pasa los mismos argumentos. UpdateManyModel actualiza todos los documentos que coincidan con su filtro de query.
El siguiente ejemplo crea una instancia de UpdateManyModel:
UpdateManyModel<Document> operation = new UpdateManyModel<>( eq("name", "Mongo's Deli"), set("cuisine", "Sandwiches and Salads"));
Reemplazar operaciones
Una operación de reemplazo remueve todos los campos y valores de un documento especificado, excepto el campo _id, y los reemplaza con otros nuevos. Para realizar una operación de reemplazo, crea una instancia de ReplaceOneModel y pasa un filtro de query, así como los campos y valores que quieras almacenar en el documento correspondiente.
El siguiente ejemplo crea una instancia de ReplaceOneModel:
ReplaceOneModel<Document> operation = new ReplaceOneModel<>( eq("name", "Original Pizza"), new Document("name", "Mongo's Pizza") .append("borough", "Manhattan"));
Si varios documentos coinciden con el filtro de query especificado en la instancia ReplaceOneModel, la operación reemplaza el primer resultado. Puedes especificar una medida en una instancia ReplaceOptions para aplicar un orden a los documentos coincidentes antes de que el servidor realice la operación de reemplazo, como se muestra en el siguiente código:
ReplaceOptions options = ReplaceOptions.sort(Sorts.ascending("_id"));
Tip
Reemplazar múltiples documentos
Para reemplazar varios documentos, crear una instancia de ReplaceOneModel para cada documento.
Operaciones de borrar
Para borrar un documento, crea una instancia de DeleteOneModel y pasa un filtro de query especificando el documento que deseas borrar. DeleteOneModel elimina solo el primer documento que coincide con el filtro de query.
El siguiente ejemplo crea una instancia de DeleteOneModel:
DeleteOneModel<Document> operation = new DeleteOneModel<>( eq("restaurant_id", "5678"));
Para borrar varios documentos, crea una instancia de DeleteManyModel y pasa un filtro de query que especifique los documentos que deseas borrar. DeleteManyModel remueve todos los documentos que coinciden con tu filtro de query.
El siguiente ejemplo crea una instancia de DeleteManyModel:
DeleteManyModel<Document> operation = new DeleteManyModel<>( eq("name", "Mongo's Deli"));
Realizar la Operación Masiva
Después de definir una instancia de WriteModel para cada operación que desee realizar, pase una lista de estas instancias al método bulkWrite(). Por defecto, el método ejecuta las operaciones en el orden en que se definen en la lista.
El siguiente ejemplo realiza múltiples operaciones de escritura usando el método bulkWrite():
Publisher<BulkWriteResult> bulkWritePublisher = restaurants.bulkWrite( Arrays.asList(new InsertOneModel<>( new Document("name", "Mongo's Deli") .append("cuisine", "Sandwiches") .append("borough", "Manhattan") .append("restaurant_id", "1234")), new InsertOneModel<>(new Document("name", "Mongo's Deli") .append("cuisine", "Sandwiches") .append("borough", "Brooklyn") .append("restaurant_id", "5678")), new UpdateManyModel<>(eq("name", "Mongo's Deli"), set("cuisine", "Sandwiches and Salads")), new DeleteOneModel<>(eq("restaurant_id", "1234")))); BulkWriteResult bulkResult = Mono.from(bulkWritePublisher).block(); System.out.println(bulkResult.toString());
AcknowledgedBulkWriteResult{insertedCount=2, matchedCount=2, removedCount=1, modifiedCount=2, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=66a7e0a6c08025218b657208}}, BulkWriteInsert{index=1, id=BsonObjectId{value=66a7e0a6c08025218b657209}}]}
Si alguna de las operaciones de escritura falla, el controlador Java Reactive Streams señala un MongoBulkWriteException y no realiza ninguna otra operación individual. MongoBulkWriteException incluye un BulkWriteError al que se puede acceder utilizando el método MongoBulkWriteException.getWriteErrors(), el cual proporciona detalles sobre la falla individual.
Nota
Cuando el controlador de Java Reactive Streams ejecuta una operación por lotes, utiliza el writeConcern de la colección en la que se está ejecutando la operación. El driver reporta 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.
Personalizar guardado masivo
La clase BulkWriteOptions contiene métodos que modifican el comportamiento del método bulkWrite(). Para usar la clase BulkWriteOptions, construya una nueva instancia de la clase y, a continuación, llame a uno o más de sus métodos para modificar la operación de guardar. Puede encadenar estas llamadas de método juntas. Para modificar el comportamiento de la operación de guardar, pasa la instancia de la clase como el último argumento al método bulkWrite().
Puedes utilizar los siguientes métodos en la clase BulkWriteOptions para modificar un método de guardar. Todos los métodos son opcionales.
Método | Descripción |
|---|---|
| Specifies whether the bulk write operation bypasses document validation. This lets you
perform write operations on documents that don't meet the schema validation requirements, if any
exist. For more information about schema validation, see Schema
Validation in the MongoDB
Server manual. |
| Attaches a Bson comment to the operation. For more information, see the insert command
fields guide in the
MongoDB Server manual. |
| Attaches a String comment to the operation. For more information, see the insert command
fields guide in the
MongoDB Server manual. |
| Specifies 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. |
| If set to True, the driver performs the individual operations in the order
provided. If an individual operation fails, the driver will not execute any
subsequent individual operations.Defaults to True. |
El siguiente ejemplo llama al método bulkWrite() del ejemplo anterior, pero establece la opción ordered en False:
Publisher<BulkWriteResult> bulkWritePublisher = restaurants.bulkWrite( Arrays.asList(new InsertOneModel<>( new Document("name", "Mongo's Deli") .append("cuisine", "Sandwiches") .append("borough", "Manhattan") .append("restaurant_id", "1234")), new InsertOneModel<>(new Document("name", "Mongo's Deli") .append("cuisine", "Sandwiches") .append("borough", "Brooklyn") .append("restaurant_id", "5678")), new UpdateManyModel<>(eq("name", "Mongo's Deli"), set("cuisine", "Sandwiches and Salads")), new DeleteOneModel<>(eq("restaurant_id", "1234"))), new BulkWriteOptions().ordered(false)); BulkWriteResult bulkResult = Mono.from(bulkWritePublisher).block(); System.out.println(bulkResult.toString());
AcknowledgedBulkWriteResult{insertedCount=2, matchedCount=2, removedCount=1, modifiedCount=2, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=66a7e03cce430c5854b6caf9}}, BulkWriteInsert{index=1, id=BsonObjectId{value=66a7e03cce430c5854b6cafa}}]}
Si alguna de las operaciones de escritura en una escritura masiva desordenada falla, el driver de Java Reactive Streams 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.
Guardado Masivo del Cliente
Al conectarse a una implementación que ejecuta MongoDB Server 8.0 o posterior, puede utilizar el método MongoClient.bulkWrite() para guardar en múltiples bases de datos y colecciones en el mismo clúster. El método MongoClient.bulkWrite() realiza todas las operaciones de escritura en una sola llamada.
El método MongoClient.bulkWrite() toma una lista de instancias ClientNamespacedWriteModel para representar diferentes operaciones de escritura. Puedes construir instancias de la interfaz ClientNamespacedWriteModel utilizando métodos de instancia. Por ejemplo, una instancia de ClientNamespacedInsertOneModel representa una operación para insertar un documento, y puedes crear este modelo utilizando el método ClientNamespacedWriteModel.insertOne().
Los modelos y sus correspondientes métodos de instancia se describen en la siguiente tabla.
Modelo | Método de instancia | Descripción | Parámetros |
|---|---|---|---|
|
| Crea un modelo para insertar un documento en el |
|
|
| Crea un modelo para actualizar el primer documento en el |
Debes pasar un valor para el parámetro |
|
| Crea un modelo para actualizar todos los documentos en el |
Debes pasar un valor para el parámetro |
|
| Crea un modelo para reemplazar el primer documento en el |
|
|
| Crea un modelo para borrar el primer documento en |
|
|
| Crea un modelo para borrar todos los documentos en |
|
Las siguientes secciones proporcionan algunos ejemplos de cómo crear modelos y utilizar el método de cliente bulkWrite().
Operaciones de inserción
Este ejemplo muestra cómo crear modelos que contienen instrucciones para insertar dos documentos. Un documento se inserta en la colección db.people y el otro documento se inserta en la colección db.things. La instancia MongoNamespace define la base de datos y la colección de destino a las que se aplica cada operación de guardar.
ClientNamespacedInsertOneModel personToInsert = ClientNamespacedWriteModel .insertOne( new MongoNamespace("db", "people"), new Document("name", "Julia Smith") ); ClientNamespacedInsertOneModel thingToInsert = ClientNamespacedWriteModel .insertOne( new MongoNamespace("db", "things"), new Document("object", "washing machine") );
Operaciones de actualizar
El siguiente ejemplo muestra cómo utilizar el método bulkWrite() para actualizar documentos existentes en las colecciones db.people y db.things:
ClientNamespacedUpdateOneModel personUpdate = ClientNamespacedWriteModel .updateOne( new MongoNamespace("db", "people"), Filters.eq("name", "Freya Polk"), Updates.inc("age", 1) ); ClientNamespacedUpdateManyModel thingUpdate = ClientNamespacedWriteModel .updateMany( new MongoNamespace("db", "things"), Filters.eq("category", "electronic"), Updates.set("manufacturer", "Premium Technologies") );
Este ejemplo incrementa el valor del campo age por 1 en el documento que tiene un valor name de "Freya Polk" en la colección people. También establece el valor del campo manufacturer en "Premium Technologies" en todos los documentos que tienen un valor de category de "electronic" en la colección things.
Si varios documentos coinciden con el filtro de query especificado en una instancia de ClientNamespacedUpdateOneModel, la operación actualiza el primer resultado. Puedes especificar un orden de clasificación en una ClientUpdateOneOptions instancia para aplicar un orden a los documentos coincidentes antes de que el servidor realice la operación de actualización, como se muestra en el siguiente código:
ClientUpdateOneOptions options = ClientUpdateOneOptions .clientUpdateOneOptions() .sort(Sorts.ascending("_id"));
Reemplazar operaciones
El siguiente ejemplo muestra cómo crear modelos para reemplazar documentos existentes en las colecciones db.people y db.things:
ClientNamespacedReplaceOneModel personReplacement = ClientNamespacedWriteModel .replaceOne( new MongoNamespace("db", "people"), Filters.eq("_id", 1), new Document("name", "Frederic Hilbert") ); ClientNamespacedReplaceOneModel thingReplacement = ClientNamespacedWriteModel .replaceOne( new MongoNamespace("db", "things"), Filters.eq("_id", 1), new Document("object", "potato") );
Después de que este ejemplo se ejecute correctamente, el documento que tiene un valor _id de 1 en la colección people se reemplaza por un documento nuevo. El documento en la colección things que tiene un valor _id de 1 se reemplaza con un nuevo documento.
Si varios documentos coinciden con el filtro de query especificado en una instancia de ClientNamespacedReplaceOneModel, la operación reemplaza el primer resultado. Puedes especificar un orden de clasificación en una instancia de ClientReplaceOneOptions para aplicar un orden a los documentos coincidentes antes de que el servidor realice la operación de reemplazo, tal como se muestra en el siguiente código:
ClientReplaceOneOptions options = ClientReplaceOneOptions .clientReplaceOneOptions() .sort(Sorts.ascending("_id"));
Realizar la Operación Masiva
Después de definir una instancia de ClientNamespacedWriteModel para cada operación que desee realizar, pase una lista de estas instancias al método del cliente bulkWrite(). Por defecto, el método ejecuta las operaciones en el orden en que se especifican.
El siguiente ejemplo realiza múltiples operaciones de escritura usando el método bulkWrite():
MongoNamespace peopleNamespace = new MongoNamespace("db", "people"); MongoNamespace thingsNamespace = new MongoNamespace("db", "things"); List<ClientNamespacedWriteModel> bulkOperations = Arrays.asList( ClientNamespacedWriteModel .insertOne( peopleNamespace, new Document("name", "Corey Kopper") ), ClientNamespacedWriteModel .replaceOne( thingsNamespace, Filters.eq("_id", 1), new Document("object", "potato") ) ); Publisher<ClientBulkWriteResult> bulkWritePublisher = mongoClient .bulkWrite(bulkOperations); ClientBulkWriteResult clientBulkResult = Mono .from(bulkWritePublisher) .block(); System.out.println(clientBulkResult.toString());
AcknowledgedSummaryClientBulkWriteResult{insertedCount=1, matchedCount=1, ...}
Si cualquiera de las operaciones de escritura falla, el driver genera un ClientBulkWriteException y no realiza ninguna otra operación individual. ClientBulkWriteException incluye un BulkWriteError al cual se puede acceder utilizando el método ClientBulkWriteException.getWriteErrors(), que proporciona detalles de la falla individual.
Personalizar guardado masivo
Puede pasar una instancia de ClientBulkWriteOptions al método bulkWrite() para personalizar cómo el controlador ejecuta la operación de escritura masiva.
Orden de ejecución
Por defecto, el controlador ejecuta las operaciones individuales en una operación masiva en el orden en que las especifiques hasta que se produzca un error, o hasta que la operación se complete con éxito.
Sin embargo, puedes pasar false al método ordered() al crear una instancia de ClientBulkWriteOptions para indicar al driver que realice las operaciones de guardar de manera desordenada. Al usar la opción no ordenada, una operación que produce un error no impide que el driver realice otras operaciones de guardar en la operación de guardar masiva.
El siguiente código establece la opción ordered en false en una instancia de ClientBulkWriteOptions y realiza una operación de escritura masiva para insertar varios documentos.
MongoNamespace namespace = new MongoNamespace("db", "people"); ClientBulkWriteOptions options = ClientBulkWriteOptions .clientBulkWriteOptions() .ordered(false); List<ClientNamespacedWriteModel> bulkOperations = Arrays.asList( ClientNamespacedWriteModel.insertOne( namespace, new Document("_id", 1).append("name", "Rudra Suraj") ), // Causes a duplicate key error ClientNamespacedWriteModel.insertOne( namespace, new Document("_id", 1).append("name", "Mario Bianchi") ), ClientNamespacedWriteModel.insertOne( namespace, new Document("name", "Wendy Zhang") ) ); Publisher<ClientBulkWriteResult> bulkWritePublisher = mongoClient .bulkWrite(bulkOperations, options);
Aunque la operación de guardar que inserta un documento con una clave duplicada resulta en un error, las otras operaciones se realizan porque la operación de guardar no es ordenada.
Información Adicional
Para aprender cómo realizar operaciones de guardar individuales, consulta los siguientes guías:
Documentación de la API
Para aprender más sobre cualquiera de los métodos o tipos analizados en esta guía, consulta la siguiente documentación de API:
Guardar masivo de colecciones
Guardado Masivo del Cliente