Overview
本页面对官方MongoDB Kotlin驱动程序和社区开发的 KMongo驱动程序的大多数区别进行了高级比较。您可以使用此页面来确定从已弃用的 KMongo驱动程序迁移到官方MongoDB Kotlin驱动程序需要进行哪些更改。
KMongo 是一个流行的社区开发的库,用于在 Kotlin 应用程序中使用 MongoDB。它是在官方 Kotlin 驱动程序创建之前为满足 Kotlin Community 的需求而创建的 Java 驱动程序的包装器。
重要
自 2023 年 7 月起,KMongo 已被标记为已弃用。
MongoDB Kotlin 驱动程序是官方支持和维护的适用于 Kotlin 的 MongoDB 驱动程序。它由 MongoDB 团队开发。
尽管这两个驱动程序都支持同步和异步操作,但本页上的示例将使用基于异步协程的操作。
Kotlin驱动程序与 KMongo 的差异
Kotlin 驱动程序是 Kotlin 的官方 MongoDB 驱动程序。 它由 MongoDB 团队开发,为 Kotlin 应用程序连接到 MongoDB 并处理数据提供原生 API。 它是通过包装MongoDB Java 驱动程序来实现的。
KMongo 是一个流行的社区开发的库,用于在 Kotlin 应用程序中使用 MongoDB。它是在官方 Kotlin 驱动程序创建之前为满足 Kotlin Community 的需求而创建的 Java 驱动程序的包装器。
重要
自 2023 年 7 月起,KMongo 已被标记为已弃用。
Kotlin 驱动程序是与 KMongo 创建者 Julien Buret 合作开发的,旨在为用户提供官方支持的驱动程序。
官方 Kotlin 驱动程序和 KMongo 通常具有相似的 API。 Kotlin 驱动程序和 KMongo 之间的显着相似之处包括:
支持同步和基于协程的操作
支持使用数据类表示 MongoDB 文档
支持 KotlinX 序列化
支持MongoDB 增删改查 API和聚合API
虽然官方 Kotlin 驱动程序和 KMongo 很相似,但存在一些关键区别:
连接到 MongoDB cluster
这两个驱动程序都允许您从 Kotlin 应用程序连接到 MongoDB 集群并与之通信。
要使用MongoDB Kotlin驱动程序连接到MongoDB 集群:
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")
有关更多信息,请参阅连接到MongoDB文档。
要使用带有协程的 KMongo 连接到MongoDB 集群,请执行以下操作:
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>()
与MongoDB Kotlin驱动程序不同,KMongo 允许从数据类名称推断集合名称。
CRUD 和聚合
这两个驱动程序都支持所有 MongoDB CRUD API 和聚合操作。
提示
如果您习惯使用 KMongo 中提供的中缀表示法构造查询筛选条件,则还可以使用此表示法通过 mongodb-driver-kotlin-extensions包中的扩展方法在官方Kotlin驱动程序中创建过滤器。选择 Kotlin Driver Extensions标签页,查看在Kotlin驱动程序中使用此查询语法的示例。
MongoDB Kotlin驱动程序还为所有基本增删改查操作提供了函数:
// 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)
您可以使用 aggregate() 方法和 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) }
您可以使用 mongodb-driver-kotlin-extensions 库中的 Builders API ,通过数据类属性直接创建查询筛选器和聚合管道阶段。 该库还允许您使用中缀表示法创建查询:
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)
KMongo 为所有基本CRUD操作提供了函数:
// 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")
可以使用aggregate方法和pipeline函数构建聚合管道:
val avgAge = collection.aggregate<Double>( pipeline( match(Jedi::name ne "Luke Skywalker"), group(Jedi::name, avg(Jedi::age)) ) ).toList()
构建查询
这两个驱动程序都支持使用属性引用的类型安全查询。
提示
如果您习惯使用 KMongo 中提供的中缀表示法构造查询筛选条件,则还可以使用此表示法通过 mongodb-driver-kotlin-extensions包中的扩展方法在官方Kotlin驱动程序中创建过滤器。选择 Kotlin Driver Extensions标签页,查看在Kotlin驱动程序中使用此查询语法的示例。
MongoDB Kotlin驱动程序使用 Builders API来构造查询。 或者,您可以使用 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)
要将 KMongo 字符串查询映射到 Kotlin 驱动程序,您可以使用JsonObject类。
val query = JsonObject("{\"name\": \"Gabriel Garc\\u00eda M\\u00e1rquez\"}") val jsonResult = collection.find(query).firstOrNull()
有关更多信息,请参阅以下 Kotlin 驱动程序文档:
文档指南
JsonObject API文档
您可以使用 mongodb-driver-kotlin-extensions 库中的 Builders API直接构建对数据类属性的查询。 该库还允许您使用中缀表示法创建查询:
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)
借助 KMongo,您可以使用对表示集合中对象的数据类的属性引用以及库提供的中缀运算符来创建查询。
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 还支持string查询,可让您使用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()
有关更多信息,请参阅以下 KMongo 文档:
数据类型
这两个驱动程序都支持使用Kotlin数据类和 Document 类对存储在MongoDB集合中的数据进行建模。 Document 类允许您以灵活的格式对MongoDB集合中表示的数据进行建模。
您可以使用数据类和 Document 类,通过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")
您可以使用数据类和Document类在 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")
数据序列化
这两个驱动程序都支持在 Kotlin 中将数据对象与 BSON 进行序列化和反序列化。
您可以使用自动数据类编解码器和 kotlinx.serialization 库在Kotlin驱动程序中序列化数据类。该驱动程序提供了一个高效的 Bson 序列化器,用于处理Kotlin对象到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 )
要了解更多信息,请参阅Kotlin 序列化文档。
如果使用Document类表示collection,则可以使用.toJson()方法将其序列化为 JSON 和 EJSON:
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)
要了解有关使用Document类序列化数据的更多信息,请参阅文档数据格式 - 扩展 JSON文档。
您可以使用以下序列化库在 KMongo 中序列化数据:
Jackson(默认)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)
要学习;了解有关 KMongo 序列化方法的更多信息,请参阅对象映射 KMongo 文档。
同步和异步支持
这两个驱动程序都支持同步和异步操作。
MongoDB Kotlin驱动程序还具有用于同步和异步操作的单独库。但是,Kotlin驱动程序仅内置支持将协程作为异步范例。MongoDB Kotlin驱动程序目前不支持其他异步范例,例如响应式流、Reactor 或 RxJava2。
驱动 | 安装包 |
|---|---|
同步 | com.mongodb.kotlin.client |
协程 | com.mongodb.kotlin.client.coroutine |
与 KMongo 不同,如果要编写异步代码,只需导入相关包即可。
要编写同步代码:
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)
要编写异步协程代码,请执行以下操作:
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 有一个具有主要功能的核心库org.litote.kmongo:kmongo和为核心库提供异步支持的独立伴随库。
KMongo 支持以下异步范例:
异步样式 | 安装包 |
|---|---|
反应流 | org.litote.kmongo:kmongo-async |
协程 | com.mongodb.kotlin.client.coroutine and org.litote.kmongo.coroutine |
Reactor | org.litote.kmongo:kmongo-reactor |
RxJava2 | org.litote.kmongo:kmongo-rxjava2 |
要使用 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")
要使用 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") }
要学习;了解更多信息,请参阅 KMongo 文档中的快速入门。
下一步
现在您已经了解了 KMongo 和 MongoDB Kotlin 驱动程序之间的区别,请参阅快速入门以开始使用 KMongo Kotlin 驱动程序。