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. Está desarrollado por el equipo de MongoDB y proporciona una API nativa para que las aplicaciones Kotlin se conecten a MongoDB y trabajen con datos. Se implementa envolviendo el MongoDB Java driver.
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 de Kotlin se desarrolló en colaboración con el creador de KMongo, Julien Buret, para ofrecer a los usuarios un controlador respaldado oficialmente.
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
Soporte usando 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éctate a MongoDB documentación para 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 MongoDB Kotlin Driver, KMongo permite inferir el nombre de la colección a partir del nombre de la clase de datos.
CRUD y agregación
Ambos controladores proporcionan soporte para todas las API CRUD de MongoDB y operaciones de agregación.
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 de la 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 MongoDB Kotlin Driver 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)
Puedes compilar pipelines de agregación usando 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 construir pipelines de agregación usando 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 drivers brindan soporte para consultas de tipo seguro 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 mapear una query de string de KMongo al driver de Kotlin, puedes usar 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:
documento guide
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:
Tipado de datos
Ambos drivers 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 te 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")
Puedes 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 ofrecen 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, consulta la documentación de KMongo sobre Mapeo de objetos.
Soporte Síncrono y Asíncrono
Ambos controladores admiten operaciones síncronas y asíncronas.
El driver de MongoDB para Kotlin también tiene librerías separadas para operaciones síncronas y asíncronas. Sin embargo, el driver de Kotlin solo tiene funcionalidad incorporada para corrutinas como un paradigma asíncrono. El controlador de MongoDB Kotlin actualmente no proporciona soporte para 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 librería principal org.litote.kmongo:kmongo con funcionalidades principales y librerías complementarias separadas que proporcionan soporte asincrónico a la librería principal.
KMongo admite los siguientes paradigmas asíncronos:
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 guardar 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 ha aprendido sobre las diferencias entre KMongo y el controlador MongoDB Kotlin, consulta la Guía de inicio rápido para comenzar a utilizar el controlador KMongo Kotlin.