Overview
Esta página contiene una comparación de alto nivel de la mayoría de las formas en que difieren el controlador oficial MongoDB Kotlin y el controlador desarrollado por la comunidad KMongo. Puedes utilizar esta página para identificar los cambios que necesitas realizar para migrar del controlador KMongo obsoleto al controlador oficial de MongoDB Kotlin.
KMongo es una popular librería desarrollada por la comunidad para trabajar con MongoDB desde aplicaciones en Kotlin. Es un contenedor alrededor del driver de Java que fue creado antes que el driver oficial de Kotlin para servir las necesidades de la Community de Kotlin.
Importante
A partir de julio de 2023, KMongo ha sido marcado como obsoleto.
El controlador MongoDB para Kotlin es el único controlador de MongoDB para Kotlin oficialmente soportado y mantenido. Es desarrollado por el equipo de MongoDB.
Aunque ambos controladores soportan operaciones síncronas y asíncronas, los ejemplos en esta página utilizarán operaciones asíncronas basadas en corutinas.
Diferencias del controlador de Kotlin con KMongo
El controlador Kotlin es el controlador oficial de MongoDB para Kotlin. Desarrollado por el equipo de MongoDB, proporciona una API nativa para que las aplicaciones Kotlin se conecten a MongoDB y trabajen con datos. Se implementa encapsulando el controlador Java de MongoDB.
KMongo es una popular librería desarrollada por la comunidad para trabajar con MongoDB desde aplicaciones en Kotlin. Es un contenedor alrededor del driver de Java que fue creado antes que el driver oficial de Kotlin para servir las necesidades de la Community de Kotlin.
Importante
A partir de julio de 2023, KMongo ha sido marcado como obsoleto.
El controlador Kotlin se desarrolló en colaboración con el creador de KMongo, Julien Buret, para ofrecer a los usuarios un controlador con soporte oficial.
El controlador oficial de Kotlin y KMongo tienen APIs generalmente similares. Las similitudes notables entre el controlador de Kotlin y KMongo incluyen:
Soporte para operaciones síncronas y basadas en corrutinas
Admite el uso de clases de datos para representar documentos MongoDB
Compatibilidad con la serialización de KotlinX
Compatibilidad con la API CRUD de MongoDB y la API de agregación
Aunque el controlador oficial de Kotlin y KMongo son similares, existen algunas diferencias clave:
Conectarse al clúster de MongoDB
Ambos drivers te permiten conectarte y comunicarte con clústeres de MongoDB desde una aplicación Kotlin.
Para conectar a un clúster de MongoDB utilizando el controlador de MongoDB Kotlin:
import com.mongodb.kotlin.client.coroutine.MongoClient data class Jedi(val name: String, val age: Int) // Replace the placeholder with your MongoDB deployment's connection string val uri = CONNECTION_STRING_URI_PLACEHOLDER val mongoClient = MongoClient.create(uri) val database = mongoClient.getDatabase("test") // Get a collection of documents of type Jedi val collection = database.getCollection<Jedi>("jedi")
Ver el Conéctese a la documentación de MongoDB para obtener más información.
Para conectarse a un clúster de MongoDB usando KMongo con corutinas:
import org.litote.kmongo.reactivestreams.* import org.litote.kmongo.coroutine.* data class Jedi(val name: String, val age: Int) // Get new MongoClient instance using coroutine extension val client = KMongo.createClient().coroutine val database = client.getDatabase("test") // Get a collection of documents of type Jedi val col = database.getCollection<Jedi>()
A diferencia del controlador Kotlin de MongoDB, KMongo permite inferir el nombre de la colección a partir del nombre de la clase de datos.
CRUD y agregación
Ambos controladores brindan soporte para todas las API CRUD y operaciones de agregación de MongoDB.
Tip
Si está acostumbrado a construir filtros de consulta mediante la notación infija disponible en KMongo, también puede usar esta notación para crear filtros en el controlador oficial de Kotlin mediante el uso de métodos de extensión de mongodb-driver-kotlin-extensions paquete. Elija el Kotlin Driver Extensions pestaña para ver un ejemplo que usa esta sintaxis de query en el driver de Kotlin.
El controlador MongoDB Kotlin también proporciona funciones para todas las operaciones CRUD básicas:
// Insert a document val jedi = Jedi("Luke Skywalker", 19) collection.insertOne(jedi) // Find a document val luke = collection.find(Jedi::name.name, "Luke Skywalker") val jedis = collection.find(lt(Jedi::age.name, 30)).toList() // Update a document val filter = Filters.eq(Jedi::name.name, "Luke Skywalker") val update = Updates.set(Jedi::age.name, 20) collection.updateOne(filter, update) // Delete a document val filter = Filters.eq(Jedi::name.name, "Luke Skywalker") collection.deleteOne(filter)
Puede crear canales de agregación utilizando el método aggregate() y la función pipeline:
data class Results(val avgAge: Double) val resultsFlow = collection.aggregate<Results>( listOf( Aggregates.match(Filters.ne(Jedi::name.name, "Luke Skywalker")), Aggregates.group("\$${Jedi::name.name}", Accumulators.avg("avgAge", "\$${Jedi::age.name}")) ) ) resultsFlow.collect { println(it) }
Consulta la documentación de Operaciones CRUD y Agregación para obtener más información.
Puedes usar la API de Builders de la biblioteca mongodb-driver-kotlin-extensions para crear filtros de query y etapas del pipeline de agregación directamente utilizando propiedades de clases de datos. Esta librería también permite crear queries usando notación infija:
import com.mongodb.kotlin.client.model.Filters.eq import com.mongodb.kotlin.client.model.Filters.lt import com.mongodb.kotlin.client.model.Updates.set data class Jedi(val name: String, val age: Int) // Find documents val luke = collection.find(Jedi::name eq "Luke Skywalker") val jedis = collection.find(Jedi::age lt 30)).toList() // Update a document val filter = Jedi::name eq "Luke Skywalker" val update = Jedi::age.name set 20 collection.updateOne(filter, update) // Delete a document val filter = Jedi::name eq "Luke Skywalker" collection.deleteOne(filter)
Para aprender más y ver ejemplos que usan todas las clases de desarrolladores, consulta la guía Usa Desarrolladores con Clases de Datos.
KMongo proporciona funciones para todas las operaciones CRUD básicas:
// Insert a document val jedi = Jedi("Luke Skywalker", 19) col.insertOne(jedi) // Find a document val luke = col.findOne(Jedi::name eq "Luke Skywalker") val jedis = col.find(Jedi::age lt 30).toList() // Update a document col.updateOne(Jedi::name eq "Luke Skywalker", setValue(Jedi::age, 20)) // Delete a document col.deleteOne(Jedi::name eq "Luke Skywalker")
Se pueden crear canalizaciones de agregación utilizando el método aggregate y la función pipeline:
val avgAge = collection.aggregate<Double>( pipeline( match(Jedi::name ne "Luke Skywalker"), group(Jedi::name, avg(Jedi::age)) ) ).toList()
Para obtener más información sobre los métodos disponibles, consulta la Descripción general de extensiones documentación de KMongo.
Construir Consultas
Ambos controladores proporcionan soporte para consultas de tipos seguros utilizando referencias de propiedad.
Tip
Si estás acostumbrado a construir filtros de query utilizando la notación infija disponible en KMongo, también puedes usar esta notación para crear filtros en el driver oficial de Kotlin usando métodos de extensión del paquete mongodb-driver-kotlin-extensions. Selecciona la pestaña Kotlin Driver Extensions para ver un ejemplo que utilice esta sintaxis de query en el driver de Kotlin.
El driver de MongoDB para Kotlin utiliza la API de desarrolladores para construir queries. Como alternativa, puedes usar la clase Document.
data class Person(val name: String, val email: String, val gender: String, val age: Int) data class Results(val email: String) val collection = database.getCollection<Person>("people") // Using Builders val filter = and(eq("gender", "female"), gt("age", 29)) val projection = fields(excludeId(), include("email")) val results = collection.find<Results>(filter).projection(projection) // Using Document class val filter = Document().append("gender", "female").append("age", Document().append("\$gt", 29)) val projection = Document().append("_id", 0).append("email", 1) val results = collection.find<Results>(filter).projection(projection)
Para asignar una consulta de cadena KMongo al controlador Kotlin, puede utilizar la clase JsonObject.
val query = JsonObject("{\"name\": \"Gabriel Garc\\u00eda M\\u00e1rquez\"}") val jsonResult = collection.find(query).firstOrNull()
Para más información, consulta la siguiente documentación del controlador de Kotlin:
JsonObject Documentación de API
Puedes utilizar la Builders API de la librería mongodb-driver-kotlin-extensions para construir consultas directamente en las propiedades de la clase de datos. Esta librería también permite crear queries usando notación infija:
import com.mongodb.kotlin.client.model.Filters.eq import com.mongodb.kotlin.client.model.Filters.and import com.mongodb.kotlin.client.model.Filters.gt import com.mongodb.kotlin.client.model.Projections.excludeId import com.mongodb.kotlin.client.model.Projections.fields import com.mongodb.kotlin.client.model.Projections.include data class Person(val name: String, val gender: String, val age: Int) data class Result(val name: String) val collection = database.getCollection<Person>("people") // Infix Notation Query val filter = (Person::gender eq "female") and (Person::age gt 29)) val projection = fields(excludeId(), include(Person::name)) val results = collection.find<Result>(filter).projection(projection)
Para aprender más y ver ejemplos que usan todas las clases de desarrolladores, consulta la guía Usa Desarrolladores con Clases de Datos.
Con KMongo, puedes crear consultas mediante referencias de propiedades en la clase de datos que representa objetos en una colección y operadores infijos que proporciona la librería.
data class Jedi(val name: String) val yoda = col.findOne(Jedi::name eq "Yoda") // Compile error (2 is not a String) val error = col.findOne(Jedi::name eq 2) // Use property reference with instances val yoda2 = col.findOne(yoda::name regex "Yo.*")
KMongo también admite string de consultas que te permiten crear consultas con el Lenguaje de Consulta MongoDB:
import org.litote.kmongo.MongoOperator.lt import org.litote.kmongo.MongoOperator.match import org.litote.kmongo.MongoOperator.regex import org.litote.kmongo.MongoOperator.sample val yoda = col.findOne("{name: {$regex: 'Yo.*'}}")!! val luke = col.aggregate<Jedi>("""[ {$match:{age:{$lt : ${yoda.age}}}}, {$sample:{size:1}} ]""").first()
Para obtener más información, consulte la siguiente documentación de KMongo:
Tipificación de datos
Ambos controladores admiten el uso de clases de datos de Kotlin y la clase Document para modelar los datos almacenados en una colección de MongoDB. La clase Document permite modelar los datos representados en una colección de MongoDB en un formato flexible.
Puede utilizar clases de datos y clases Document para modelar datos con el controlador MongoDB Kotlin:
// With data class data class Movie(val title: String, val year: Int, val rating: Float) val dataClassCollection = database.getCollection<Movie>("movies") val movieDataClass = dataClassCollection.findOneOrNull() val movieNameDataClass = movieDataClass.title // With Document class val documentCollection = database.getCollection<Movie>("movies") val movieDocument = documentCollection.findOneOrNull() val movieTitleDocument = movieDocument.getString("title")
Puede utilizar clases de datos y clases Document para modelar datos en KMongo:
// With data class data class Movie(val title: String, val year: Int, val rating: Float) val collection = database.getCollection<Movie>("movies") val movieDataClass = dataClassCollection.findOne() val movieNameDataClass = movieDataClass.title // With Document class val documentCollection = database.getCollection("movies") val movieDocument = documentCollection.findOne() val movieTitleDocument = movieDocument.getString("title")
serialización de datos
Ambos controladores proporcionan soporte para serializar y deserializar objetos de datos en Kotlin hacia y desde BSON.
Puedes serializar las clases de datos en el driver de Kotlin utilizando tanto los códecs automáticos de clases de datos como la librería kotlinx.serialization. El controlador proporciona un eficiente Bson serializador que gestiona la serialización de objetos de Kotlin a datos BSON.
data class LightSaber( // Use instead of @BsonId val id: ObjectId?, val color: String, val qty: Int, val manufacturer: String = "Acme" // Use instead of @BsonProperty )
Para obtener más información, consulta la documentación de Kotlin Serialization.
Si usas la clase Document para representar tu colección, puedes serializarla a JSON y EJSON mediante el método .toJson():
val document = Document("_id", 1).append("color", "blue") // Serialize to JSON document.toJson() // Serialize to EJSON val settings = JsonWriterSettings.builder().outputMode(JsonMode.STRICT).build() val json = doc.toJson(settings)
Para obtener más información sobre la serialización de datos con la clase Document, consulta la documentación de Formato de datos de documentos - JSON extendido.
Puedes serializar datos en KMongo usando las siguientes librerías de serialización:
Jackson(por defecto)POJO Codec enginekotlinx.serialization
// Using KotlinX Serialization data class Data( val _id: Id<Data> = newId()) val json = Json { serializersModule = IdKotlinXSerializationModule } val data = Data() val json = json.encodeToString(data)
Para obtener más información sobre los métodos de serialización de KMongo, consulte la documentación de Mapeo de objetos de KMongo.
Soporte Síncrono y Asíncrono
Ambos controladores admiten operaciones síncronas y asíncronas.
El controlador Kotlin de MongoDB también cuenta con bibliotecas independientes para operaciones síncronas y asíncronas. Sin embargo, solo admite corrutinas como paradigma asíncrono. Actualmente, no es compatible con otros paradigmas asíncronos como Reactive Streams, Reactor o RxJava2.
Controlador | Paquete |
|---|---|
Sincronizar | com.mongodb.kotlin.client |
corrutina | com.mongodb.kotlin.client.coroutine |
A diferencia de KMongo, si deseas escribir código asíncrono, solo necesitas importar el paquete relevante.
Para escribir código síncrono:
import com.mongodb.kotlin.client.MongoClient // Instantiate your collection data class Jedi(val name: String, val age: Int) val uri = "<your-connection-string"> val mongoClient = MongoClient.create(uri) val database = mongoClient.getDatabase("test") val collection = database.getCollection<Jedi>("jedi") // Synchronous operations val jedi = Jedi("Luke Skywalker", 19) collection.insertOne(jedi)
Para escribir código de corrutinas asíncronas:
import com.mongodb.kotlin.client.coroutine.MongoClient // Instantiate your collection data class Jedi(val name: String, val age: Int) val uri = "<your-connection-string"> val mongoClient = MongoClient.create(uri) val database = mongoClient.getDatabase("test") val collection = database.getCollection<Jedi>("jedi") runBlocking { // Async operations val jedi = Jedi("Luke Skywalker", 19) collection.insertOne(jedi) }
KMongo tiene una biblioteca central org.litote.kmongo:kmongo con funcionalidad principal y bibliotecas complementarias separadas que brindan soporte asincrónico a la biblioteca central.
KMongo admite los siguientes paradigmas asincrónicos:
Estilo asíncrono | Paquete |
|---|---|
reactive streams | org.litote.kmongo:kmongo-async |
corrutina | com.mongodb.kotlin.client.coroutine and org.litote.kmongo.coroutine |
Reactor | org.litote.kmongo:kmongo-reactor |
RxJava2 | org.litote.kmongo:kmongo-rxjava2 |
Para escribir código sincrónico con KMongo:
import org.litote.kmongo.* // Instantiate your collection data class Jedi(val name: String, val age: Int) val client = KMongo.createClient() val database = client.getDatabase("test") val col = database.getCollection<Jedi>() // Synchronous operations col.insertOne(Jedi("Luke Skywalker", 19)) val yoda : Jedi? = col.findOne(Jedi::name eq "Yoda")
Para escribir código asíncrono de rutinas en Kotlin con KMongo:
import org.litote.kmongo.reactivestreams.* import org.litote.kmongo.coroutine.* // Instantiate your collection data class Jedi(val name: String, val age: Int) val client = KMongo.createClient() val database = client.getDatabase("test") val col = database.getCollection<Jedi>() runBlocking { // Async operations col.insertOne(Jedi("Luke Skywalker", 19)) val yoda : Jedi? = col.findOne(Jedi::name eq "Yoda") }
Para obtener más información, consulta la Guía rápida en la documentación de KMongo.
¿Qué sigue?
Ahora que conoce las diferencias entre KMongo y el controlador MongoDB Kotlin, consulte la Guía de inicio rápido para comenzar a utilizar el controlador KMongo Kotlin.