Overview
Esta guía te muestra cómo usar el driver de Scala para realizar una operación de escritura masiva que realiza múltiples cambios en tus datos en una sola llamada a la base de datos.
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.
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 Seq 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 desees realizar, crea una instancia de una de las siguientes clases que heredan de WriteModel:
InsertOneModelUpdateOneModelUpdateManyModelReplaceOneModelDeleteOneModelDeleteManyModel
Luego, pasa una lista de estas instancias al método bulkWrite().
Las siguientes secciones muestran cómo crear y utilizar instancias de las clases anteriores. La sección Realizar la operación masiva demuestra cómo pasar una lista de modelos al método bulkWrite() para realizar la operación masiva.
Datos de muestra
Los ejemplos de esta sección utilizan la restaurants colección sample_restaurants de la base de datos de los conjuntos de datos de muestra de Atlas. Para acceder a esta colección desde su aplicación Scala, cree un MongoClient que se conecte a un clúster de Atlas y asigne los siguientes valores a database las collection variables y:
val database: MongoDatabase = mongoClient.getDatabase("sample_restaurants") val collection: MongoCollection[Document] = database.getCollection("restaurants")
Para aprender cómo crear un clúster gratuito de MongoDB Atlas y cargar los conjuntos de datos de ejemplo, consulta la guía MongoDB Get Started.
Operaciones de inserción
Para realizar una operación de inserción, cree una instancia InsertOneModel y especifique el documento que desea insertar.
El siguiente ejemplo crea una instancia de InsertOneModel:
val insertOneModel = InsertOneModel( Document("name" -> "Blue Moon Grill", "borough" -> "Brooklyn", "cuisine" -> "American") )
Para insertar varios documentos, cree una instancia de InsertOneModel para cada documento.
Importante
Al realizar una operación masiva, el InsertOneModel no puede insertar un documento con un _id ya existente en la colección. En este caso, el controlador lanza un MongoBulkWriteException.
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 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 de MongoDB Server.
El siguiente ejemplo crea una instancia de UpdateOneModel:
val updateOneFilter = equal("name", "White Horse Tavern") val updateOneDoc = set("borough", "Queens") val updateOneModel = UpdateOneModel(updateOneFilter, updateOneDoc)
Si varios documentos coinciden con el filtro de query especificado en la instancia de UpdateOneModel, la operación actualiza el primer resultado. Puedes especificar una ordenación en una instancia de UpdateOptions para aplicar un orden a los documentos coincidentes antes de que el controlador realice la operación de actualización, como lo muestra el siguiente código:
val options = UpdateOptions.sort(ascending("name"))
Para actualizar varios documentos, cree una instancia de UpdateManyModel y pase los mismos argumentos que para UpdateOneModel. La UpdateManyModel clase especifica actualizaciones para todos los documentos que coinciden con su filtro de query.
El siguiente ejemplo crea una instancia de UpdateManyModel:
val updateManyFilter = equal("name", "Wendy's") val updateManyDoc = set("cuisine", "Fast food") val updateManyModel = UpdateManyModel(updateManyFilter, updateManyDoc)
Reemplazar operaciones
Una operación de reemplazo remueve todos los campos y valores de un documento especificado y los reemplaza por nuevos campos y valores que usted especifica. Para realizar una operación de reemplazo, crea una instancia de ReplaceOneModel y pasa los siguientes argumentos:
filtro de query que especifica los criterios utilizados para hacer coincidir documentos en tu colección
Documento reemplazado que especifica los nuevos campos y valores a insertar
El siguiente ejemplo crea una instancia de ReplaceOneModel:
val replaceFilter = equal("name", "Cooper Town Diner") val replaceDoc = Document("name" -> "Smith Town Diner", "borough" -> "Brooklyn", "cuisine" -> "American") val replaceOneModel = ReplaceOneModel(replaceFilter, replaceDoc)
Si varios documentos coinciden con el filtro de query especificado en la instancia ReplaceOneModel, la operación reemplaza el primer resultado. Puedes especificar un ordenamiento en una instancia ReplaceOptions para aplicar un orden a los documentos coincidentes antes de que el driver realice la operación de reemplazo, como se muestra en el siguiente código:
val options = ReplaceOptions.sort(ascending("name"))
Tip
Reemplazar múltiples documentos
Para reemplazar varios documentos, cree 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 que especifique el documento que deseas borrar. Una instancia DeleteOneModel proporciona instrucciones para eliminar solo el primer documento que coincida con tu filtro de query.
El siguiente ejemplo crea una instancia de DeleteOneModel:
val deleteOneModel = DeleteOneModel(equal("name", "Morris Park Bake Shop"))
Para borrar varios documentos, cree una instancia de DeleteManyModel y pase un filtro de query que especifique el documento que desea borrar. Una instancia de DeleteManyModel proporciona instrucciones para remover todos los documentos que coincidan con el filtro de query.
El siguiente ejemplo crea una instancia de DeleteManyModel:
val deleteManyModel = DeleteManyModel(equal("cuisine", "Experimental"))
Realizar la Operación Masiva
Después de definir una instancia de modelo para cada operación que deseas realizar, pasa una instancia Seq que contenga los modelos al método MongoCollection.bulkWrite(). Por defecto, el método ejecuta las operaciones en el orden especificado por la lista de modelos.
El siguiente ejemplo realiza múltiples operaciones de escritura usando el método bulkWrite():
val insertOneModel = InsertOneModel( Document("name" -> "Red's Pizza", "borough" -> "Brooklyn", "cuisine" -> "Pizzeria") ) val updateOneModel = UpdateOneModel(equal("name", "Moonlit Tavern"), set("borough", "Queens")) val deleteManyModel = DeleteManyModel(equal("name", "Crepe")) val writes = Seq(insertOneModel, updateOneModel, deleteManyModel) val observable = collection.bulkWrite(writes) observable.subscribe( (result: BulkWriteResult) => println(s"Success: $result"), (error: Throwable) => println(s"Error: ${error.getMessage}"), () => println("Completed") )
Success: AcknowledgedBulkWriteResult{insertedCount=1, matchedCount=1, removedCount=1, modifiedCount=1, upserts=[], inserts=[BulkWriteInsert{index=0, id=BsonObjectId{value=...}}]} Completed
Si alguna de las operaciones de escritura falla, el driver de Scala lanzará un BulkWriteError y no realizará ninguna operación adicional. BulkWriteError proporciona un elemento details que incluye la operación que falló y detalles sobre la excepción.
Nota
Cuando el controlador ejecuta una operación masiva, utiliza la preocupación de escritura de la colección de destino. El controlador informa todos los errores de preocupación de escritura después de intentar todas las operaciones, independientemente del orden de ejecución.
Personalizar escritura masiva
El método MongoCollection.bulkWrite() acepta opcionalmente un parámetro BulkWriteOptions, que especifica las opciones que puedes usar para configurar la operación de guardar masiva. Si no especifica ninguna opción, el driver realiza la operación masiva con la configuración por defecto. Para modificar el comportamiento de la operación de guardado, pasa la instancia de la clase como último argumento al método bulkWrite().
La siguiente tabla describe los métodos de establecimiento que puedes utilizar para configurar una instancia de BulkWriteOptions:
Método | 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 update operation bypasses document validation. This lets you
update 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. Defaults to false. |
| Sets a comment to attach to the operation. |
| Provides a map of parameter names and values to set top-level
variables for the operation. Values must be constant or closed
expressions that don't reference document fields. |
El siguiente código crea opciones y establece la opción ordered en false para especificar una escritura masiva desordenada. Luego, el ejemplo usa el método bulkWrite() para realizar una operación masiva:
val options = BulkWriteOptions().ordered(false) val observable = collection.bulkWrite(writes, options)
Si alguna de las operaciones de escritura en una escritura en bloque desordenada falla, el driver de Scala informa los errores solo después de intentar todas las operaciones.
Nota
Las operaciones masivas desordenadas no garantizan un orden de ejecución. El orden puede variar según la forma en que se enumeran para optimizar el tiempo de ejecución.
Valor de retorno
El método bulkWrite() devuelve un objeto SingleObservable que contiene un BulkWriteResult. Puedes obtener información de la instancia BulkWriteResult suscribiéndote al observable y usando los siguientes métodos:
Método | Descripción |
|---|---|
| Indicates if the server acknowledged the write operation. |
| The number of documents deleted, if any. |
| The number of documents inserted, if any. |
| The list of inserted documents, if any. |
| The number of documents matched for an update, if applicable. |
| The number of documents modified, if any. |
| The list of upserted documents, if any. |
Guardado Masivo del Cliente
Al conectarse a una implementación con MongoDB Server 8.0 o posterior, puede usar el método MongoClient.bulkWrite() para escribir en varias bases de datos y colecciones del mismo clúster. El método MongoClient.bulkWrite() realiza todas las operaciones de escritura en una sola llamada.
El método MongoClient.bulkWrite() toma un List que contiene una o más instancias de ClientNamespacedWriteModel para representar diferentes operaciones de guardar. 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 usando el método ClientNamespacedWriteModel.insertOne().
La siguiente tabla describe los modelos y sus métodos de instancia correspondientes:
Modelo | Método de instancia | Descripción | Parámetros |
|---|---|---|---|
|
| Crea un modelo para insertar un documento en |
|
|
| Crea un modelo para actualizar el primer documento en el |
Debe pasar un valor para el parámetro |
|
| Crea un modelo para actualizar todos los documentos en el |
Debe pasar un valor para el parámetro |
|
| Crea un modelo para reemplazar el primer documento en |
|
|
| Crea un modelo para borrar el primer documento en |
|
|
| Crea un modelo para eliminar 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.
val personToInsert = ClientNamespacedWriteModel.insertOne( MongoNamespace("db", "people"), Document("name" -> "Julia Smith") ) val thingToInsert = ClientNamespacedWriteModel.insertOne( MongoNamespace("db", "things"), 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:
val personUpdate = ClientNamespacedWriteModel.updateOne( MongoNamespace("db", "people"), equal("name", "Freya Polk"), inc("age", 1) ) val thingUpdate = ClientNamespacedWriteModel.updateMany( MongoNamespace("db", "things"), equal("category", "electronic"), 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. Puede especificar un orden de clasificación en una instancia de ClientUpdateOneOptions para aplicar un orden a los documentos coincidentes antes de que el driver realice la operación de actualización, como se muestra en el siguiente código:
val options = ClientUpdateOneOptions .clientUpdateOneOptions() .sort(ascending("_id"))
Reemplazar operaciones
El siguiente ejemplo muestra cómo crear modelos para reemplazar documentos existentes en las colecciones db.people y db.things:
val personReplacement = ClientNamespacedWriteModel.replaceOne( MongoNamespace("db", "people"), equal("_id", 1), Document("name" -> "Frederic Hilbert") ) val thingReplacement = ClientNamespacedWriteModel.replaceOne( MongoNamespace("db", "things"), equal("_id", 1), Document("object" -> "potato") )
El ejemplo de código anterior reemplaza los siguientes documentos con documentos nuevos:
Documento en la colección
peopleque tiene un valor_idde1Documento en la colección
thingsque tiene un valor_idde1
Si varios documentos coinciden con el filtro de query especificado en una instancia de ClientNamespacedReplaceOneModel, la operación reemplaza el primer resultado. Se puede especificar un orden de clasificación en una instancia de ClientReplaceOneOptions para aplicar un orden a los documentos coincidentes antes de que el driver realice la operación de reemplazo, como se muestra en el siguiente código:
val options = ClientReplaceOneOptions .clientReplaceOneOptions() .sort(ascending("_id"))
Realizar la Operación Masiva
Después de definir una instancia de ClientNamespacedWriteModel para cada operación que desea realizar, pasa una lista de estas instancias al método bulkWrite() del cliente. Por defecto, el método ejecuta las operaciones en el orden en que las especificas.
El siguiente ejemplo realiza múltiples operaciones de escritura usando el método bulkWrite():
val peopleNamespace = MongoNamespace("db", "people") val thingsNamespace = MongoNamespace("db", "things") val writeModels = List( ClientNamespacedWriteModel.insertOne( peopleNamespace, Document("name" -> "Corey Kopper") ), ClientNamespacedWriteModel.replaceOne( thingsNamespace, equal("_id", 1), Document("object" -> "potato") ) ) val observable = mongoClient.bulkWrite(writeModels) observable.subscribe( (result: ClientBulkWriteResult) => println(result.toString), (error: Throwable) => println(s"Error: ${error.getMessage}"), () => println("Completed") )
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 que se puede acceder mediante el método ClientBulkWriteException.getWriteErrors(), proporcionando información sobre el fallo.
Personalizar escritura masiva
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 en lote en el orden que usted especifique. El controlador ejecuta las operaciones hasta que ocurre un error o hasta que toda la operación por lotes se completa correctamente.
Sin embargo, puedes pasar false al método ordered() al crear una instancia de ClientBulkWriteOptions para dirigir al driver a ejecutar operaciones de guardado de manera desordenada. Si se pasa false, el controlador intenta ejecutar todas las operaciones de escritura en la operación de escritura masiva, incluso si una operación produce un error.
El siguiente código configura la opción ordered en false en una instancia de ClientBulkWriteOptions y realiza una operación de guardar masiva para insertar múltiples documentos:
val namespace = MongoNamespace("db", "people") val options = ClientBulkWriteOptions.clientBulkWriteOptions().ordered(false) val writeModels = List( ClientNamespacedWriteModel.insertOne(namespace, Document("_id" -> 1, "name" -> "Rudra Suraj")), // Causes a duplicate key error ClientNamespacedWriteModel.insertOne(namespace, Document("_id" -> 1, "name" -> "Mario Bianchi")), ClientNamespacedWriteModel.insertOne(namespace, Document("name" -> "Wendy Zhang")) ) val observable = mongoClient.bulkWrite(writeModels, options)
Debido a que la operación de escritura no está ordenada, el controlador realiza todas las operaciones que no generan errores, aunque la operación de escritura que inserta un documento con una clave duplicada genere un error.
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