Overview
En esta guía, puedes aprender a usar operaciones masivas en el controlador de Kotlin.
Para realizar una sola operación de creación, reemplazo, actualizar o borrar, puedes usar el método correspondiente. Por ejemplo, para insertar un documento y reemplazar un documento, puedes usar el insertOne() y replaceOne() métodos. Cuando utilizes estos métodos, tu cliente realizará una llamada a la base de datos por cada operación.
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: Puede usar el método
MongoCollection.bulkWrite()para realizar operaciones de guardar en lote en una sola colección. En 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 hace 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 servidor versión 8.0 o posterior, puedes utilizar el método
MongoClient.bulkWrite()para realizar operaciones de escritura en bloque en varias 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 List de WriteModel documentos al método MongoCollection.bulkWrite(). Un WriteModel es un modelo que representa una operación de escritura.
El método MongoCollection.bulkWrite() realiza cada tipo de operación de guardar en una llamada separada a la base de datos. Por ejemplo, cuando se pasan los objetos DeleteOneModel, DeleteManyModel y ReplaceOneModel al método, este realiza dos llamadas: una para las operaciones de eliminación y otra para la operación de reemplazo.
Nota
Cuando el cliente divide las operaciones en llamadas de base de datos separadas, podría reordenar las operaciones para optimizar la eficiencia si la operación de guardado masivo no está ordenada. Para aprender más sobre el orden de ejecución de operaciones, consulte la sección Orden de Ejecución.
Las siguientes secciones muestran cómo crear y usar cada documento WriteModel. Los ejemplos de cada sección utilizan los siguientes documentos de la colección people:
{ "_id": 1, "name": "Karen Sandoval", "age": 31 } { "_id": 2, "name": "William Chin", "age": 54 } { "_id": 8, "name": "Shayla Ray", "age": 20 }
Estos datos están modelados por la siguiente clase de datos de Kotlin:
data class Person( val id: Int, val name: String, val age: Int? = null, val location: String? = null )
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Operación de inserción
Para llevar a cabo una operación de inserción, crea un InsertOneModel especificando el documento que deseas insertar. Para insertar varios documentos, debe crear un InsertOneModel para cada documento que desee insertar.
Ejemplo
El siguiente ejemplo crea un InsertOneModel para dos documentos que describen a personas:
val juneDoc = InsertOneModel(Person(3, "June Carrie", 17)) val kevinDoc = InsertOneModel(Person(4, "Kevin Moss", 22))
Importante
Cuando se realiza una operación bulkWrite(), el InsertOneModel no puede insertar un documento con una _id que ya exista en la colección. En este caso, el driver muestra un MongoBulkWriteException.
El siguiente ejemplo intenta insertar dos documentos donde los valores _id son 1 y 3. Dado que ya existe un documento con un _id de 1 en la colección, la operación da como resultado un error:
try { val bulkOperations = listOf( (InsertOneModel(Person(1, "James Smith", 13))), (InsertOneModel(Person(3, "Colin Samuels"))) ) val bulkWrite = collection.bulkWrite(bulkOperations) } catch (e: MongoBulkWriteException) { println("A MongoBulkWriteException occurred with the following message: " + e.message) }
A MongoBulkWriteException occurred with the following message: Bulk write operation error on server sample-shard-00-02.pw0q4.mongodb.net:27017. Write errors: [BulkWriteError{index=0, code=11000, message='E11000 duplicate key error collection: crudOps.bulkWrite index: _id_ dup key: { _id: 1 }', details={}}].
Para aprender sobre por qué el driver no insertó el documento con el _id de 3, consulta la sección Orden de ejecución.
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la InsertOneModel documentación de la API.
Operación de reemplazo
Para realizar una operación de reemplazo, cree un ReplaceOneModel especificando un filtro de query para el documento que desea reemplazar y el documento de reemplazo.
Importante
Al realizar una bulkWrite(), el ReplaceOneModel no puede realizar cambios que violen las restricciones de índice único en la colección. Además, el modelo no realiza la operación de reemplazo si no hay coincidencias con el filtro de query.
Ejemplo
El siguiente ejemplo crea un ReplaceOneModel para reemplazar un documento donde el _id es 1 por un documento que contiene el campo adicional location:
val filter = Filters.eq("_id", 1) val insert = Person(1, "Celine Stork", location = "San Diego, CA") val doc = ReplaceOneModel(filter, insert)
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:
val opts = ReplaceOptions().sort(Sorts.ascending("_id"))
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta los siguientes recursos:
ReplaceOneModel Documentación de la API
ReplaceOptions Documentación API
Índices únicos referencia en el Manual del servidor
Operación de actualización
Para realizar una operación de actualización, cree un UpdateOneModel o UpdateManyModel que especifique un filtro de query y un documento de actualización.
El UpdateOneModel actualiza el primer documento que coincide con tu filtro de query y el UpdateManyModel actualiza todos los documentos que coinciden con tu filtro de query.
Importante
Al realizar un bulkWrite(), los tipos UpdateOneModel y UpdateManyModel no pueden realizar cambios que violen las restricciones de índices únicos en la colección. Además, los modelos no ejecutan operaciones de actualización si no hay coincidencias con el filtro de query.
Ejemplo
El siguiente ejemplo crea un UpdateOneModel para incrementar el campo age en 1 en un documento donde _id es 2:
val filter = Filters.eq("_id", 2) val update = Updates.inc(Person::age.name, 1) val doc = UpdateOneModel<Person>(filter, update)
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:
val opts = UpdateOptions().sort(Sorts.ascending("_id"))
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta los siguientes recursos:
UpdateOneModel API documentation
Documentación de API de UpdateManyModel
UpdateOptions API documentation
Explicación del Manual del Servidor de índices únicos
Borrar operación
Para realizar una operación de eliminación, cree un DeleteOneModel o un DeleteManyModel que especifique un filtro de query para los documentos que desea eliminar.
DeleteOneModel borra el primer documento que coincida con tu filtro de query y DeleteManyModel borra todos los documentos que coincidan con tu filtro de query.
Importante
Al realizar un bulkWrite(), los tipos DeleteOneModel y DeleteManyModel no eliminan ningún documento si no hay coincidencias con el filtro de query.
Ejemplo
El siguiente ejemplo crea un DeleteOneModel para borrar un documento donde el _id es 1 y un DeleteManyModel para borrar documentos donde el valor de age es menor que 30:
val deleteId1 = DeleteOneModel<Person>(Filters.eq("_id", 1)) val deleteAgeLt30 = DeleteManyModel<Person>(Filters.lt(Person::age.name, 30))
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Orden de ejecución
El método bulkWrite() acepta un BulkWriteOptions opcional como segundo parámetro para especificar si desea ejecutar las operaciones masivas como ordenadas o desordenadas.
Ejecución por orden
Por defecto, el método bulkWrite() ejecuta las operaciones en bloque en orden. Esto significa que las operaciones se ejecutan en el orden en que las agregó a la lista hasta que se produzca cualquier error.
Ejemplo
El siguiente ejemplo realiza estas operaciones masivas:
Una operación de inserción para un documento donde el
namees"Zaynab Omar"y elagees37Una operación de reemplazo para un documento donde el
_ides1con un nuevo documento que contiene el campolocationUna operación de actualización para un documento donde
_ides6para cambiar el camponameUna operación de eliminación para todos los documentos que tienen un valor de
agemayor que50
val insertMdl = InsertOneModel(Person(6, "Zaynab Omar", 37)) val replaceMdl = ReplaceOneModel( Filters.eq("_id", 1), Person(1, "Sandy Kane", location = "Helena, MT") ) val updateMdl = UpdateOneModel<Person>( Filters.eq("_id", 6), Updates.set(Person::name.name, "Zaynab Hassan") ) val deleteMdl = DeleteManyModel<Person>(Filters.gt(Person::age.name, 50)) val bulkOperations = listOf( insertMdl, replaceMdl, updateMdl, deleteMdl ) val result = collection.bulkWrite(bulkOperations)
Después de ejecutar este ejemplo, tu colección contiene el siguiente documento:
{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" } { "_id": 8, "name": "Shayla Ray", "age": 20 } { "_id": 6, "name": "Zaynab Hassan", "age": 37 }
Ejecución desordenada
También puedes ejecutar operaciones masivas en cualquier orden pasando false al método ordered() en un objeto BulkWriteOptions. Esto significa que todas las operaciones de guardar se ejecutan sin importar los errores. Si se produce algún error, el controlador lo informa al final.
El siguiente código muestra cómo ejecutar una operación masiva sin un orden de ejecución:
val options = BulkWriteOptions().ordered(false) val unorderedResult = collection.bulkWrite(bulkOperations, options)
Nota
Las operaciones masivas desordenadas no garantizan el orden de ejecución. El orden puede diferir de la forma en que los enumeras para optimizar el tiempo de ejecución.
En el ejemplo anterior, si el método bulkWrite() hubiera realizado la operación de inserción después de la operación de actualización, la operación de actualización no habría producido cambios porque el documento no existía en ese momento. La colección contendría entonces los siguientes documentos:
{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" } { "_id": 8, "name": "Shayla Ray", "age": 20 } { "_id": 6, "name": "Zaynab Omar", "age": 37 }
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Guardado Masivo del Cliente
Al conectarse a una implementación que ejecute el servidor MongoDB 8.0 o más reciente, puedes utilizar el método MongoClient.bulkWrite() para escribir en múltiples bases de datos y colecciones dentro 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 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().
Nota
Errores de guardado masivo
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.
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 ejemplos de cómo utilizar el método del cliente bulkWrite(). Los datos de muestra están modelados por las siguientes clases de datos de Kotlin:
data class Person( val id: Int, val name: String, val age: Int? = null, ) data class Object( val id: Int, val type: String, val category: String? = null, val manufacturer: String? = null, )
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Operación de inserción
Este ejemplo muestra cómo utilizar el método bulkWrite() para insertar dos documentos. Un documento se inserta en la colección sample_db.people, mientras que el otro documento se inserta en la colección sample_db.objects. La instancia MongoNamespace define las bases de datos y colecciones a las que se aplica cada operación de escritura.
val docsToInsert = mutableListOf<ClientNamespacedWriteModel>() docsToInsert.add( ClientNamespacedWriteModel .insertOne( MongoNamespace("sample_db", "people"), Person(2, "Julia Smith") ) ) docsToInsert.add( ClientNamespacedWriteModel .insertOne( MongoNamespace("sample_db", "objects"), Object(2, "washing machine") ) ) val clientBulkResult = client.bulkWrite(docsToInsert)
Operación de actualización
El siguiente ejemplo muestra cómo utilizar el método bulkWrite() para actualizar documentos existentes en las colecciones sample_db.people y sample_db.objects:
val docsToInsert = mutableListOf<ClientNamespacedWriteModel>() docsToInsert.add( ClientNamespacedWriteModel .updateOne( MongoNamespace("sample_db", "people"), Filters.eq(Person::name.name, "Freya Polk"), Updates.inc(Person::age.name, 1) ) ) docsToInsert.add( ClientNamespacedWriteModel .updateMany( MongoNamespace("sample_db", "objects"), Filters.eq(Object::category.name, "electronic"), Updates.set(Object::manufacturer.name, "Premium Technologies") ) ) val clientBulkResult = client.bulkWrite(docsToInsert)
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 objects.
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:
val options = ClientUpdateOneOptions .clientUpdateOneOptions() .sort(Sorts.ascending("_id"))
Operación de reemplazo
El siguiente ejemplo muestra cómo utilizar el método bulkWrite() para reemplazar documentos existentes en las colecciones sample_db.people y sample_db.objects.
val docsReplacements = mutableListOf<ClientNamespacedWriteModel>() docsReplacements.add( ClientNamespacedWriteModel .replaceOne( MongoNamespace("sample_db", "people"), Filters.eq(Person::id.name, 1), Person(1, "Frederic Hilbert") ) ) docsReplacements.add( ClientNamespacedWriteModel .replaceOne( MongoNamespace("sample_db", "objects"), Filters.eq(Object::id.name, 1), Object(1, "ironing board") ) ) val clientBulkResult = client.bulkWrite(docsReplacements)
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 objects 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. 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(Sorts.ascending("_id"))
Opciones de escritura masiva
Puede pasar una instancia de ClientBulkWriteOptions al método bulkWrite() para especificar opciones al ejecutar las operaciones de escritura en masa.
Orden de ejecución
Por defecto, las operaciones individuales en una operación por lotes se ejecutan en el orden en que las especificas hasta que ocurre un error o se ejecutan correctamente. No obstante, puedes pasar false al método ordered() en la interfaz ClientBulkWriteOptions para realizar operaciones de guardar de manera desordenada. Al utilizar la opción no ordenada, una operación que produce errores no impide la ejecución de otras operaciones de escritura en la llamada al método bulkWrite().
El siguiente código configura el método ordered() en una instancia de ClientBulkWriteOptions y realiza una operación de guardar masiva para insertar varios documentos.
val namespace = MongoNamespace("sample_db", "people") val options = ClientBulkWriteOptions .clientBulkWriteOptions() .ordered(false) val bulkOperations = listOf( ClientNamespacedWriteModel.insertOne( namespace, Person(2, "Rudra Suraj") ), // Causes duplicate key error ClientNamespacedWriteModel.insertOne( namespace, Person(2, "Wendy Zhang") ), ClientNamespacedWriteModel.insertOne( namespace, Person(4, "Mario Bianchi") ) ) val result = client.bulkWrite(bulkOperations, options)
Incluso si la operación de escritura que inserta un documento con una clave duplicada resulta en un error, las otras operaciones se ejecutan porque la operación de escritura no está ordenada.
Para obtener más información sobre los métodos y clases mencionados en esta sección, consulta la siguiente documentación de la API:
Resumen
MongoCollection.bulkWrite()
Para realizar una operación masiva, crea y pasa una lista de instancias de WriteModel al método bulkWrite().
Hay 6 subtipos diferentes de WriteModel: InsertOneModel, ReplaceOneModel, UpdateOneModel, UpdateManyModel, DeleteOneModel y DeleteManyModel.
Existen dos formas de ejecutar el método bulkWrite():
Ordered, que realiza las operaciones masivas en orden hasta que se produce un error, si lo hay
Sin orden, realiza todas las operaciones masivas en cualquier orden e informa de errores al final, si los hay
Para obtener más información sobre el comando de colección bulkWrite, consulte la db.collection.bulkWrite() referencia del método en el Manual del servidor MongoDB.
MongoClient.bulkWrite()
Al conectarse a una implementación que ejecuta una versión 8.0 o posterior del servidor MongoDB, puede usar el MongoClient.bulkWrite() método para realizar operaciones por lotes en varias bases de datos y colecciones a la vez.
Para realizar una operación masiva del cliente, crea una y pasa una lista de instancias ClientNamespacedWriteModel a este método.
Existen seis subtipos de ClientNamespacedWriteModel que son utilizados para representar las operaciones de guardar. Para construir estos modelos de guardado, puedes utilizar los métodos correspondientes ClientNamespacedWriteModel, insertOne(), updateOne(), updateMany(), replaceOne(), deleteOne() y deleteMany(). Estos métodos requieren un objeto MongoNamespace que define a qué base de datos y colección guardar.
El método MongoClient.bulkWrite() también puede tomar un objeto ClientBulkWriteOptions para especificar diferentes opciones sobre cómo se ejecuta el comando.
Para aprender más sobre el comando de cliente bulkWrite, consulta la referencia del método bulkWrite() en el Manual del servidor de MongoDB.