批量操作
概述
在本指南中,您可以了解如何在MongoDB Kotlin驱动程序中使用批量操作。
对于单个CRUD操作,您可以使用相关方法。例如,要插入一个文档然后更新多个文档,您可以使用insertOne()
方法和updateMany()
方法。
MongoClient
通过向每个操作对应的数据库发起请求来执行这些操作。您可以通过使用批量操作来减少对数据库的调用次数。
执行批量操作
批量操作由大量写操作组成。要执行批量操作,将包含WriteModel
文档的List
传递给bulkWrite()
方法。一个WriteModel
是一个表示单个写操作的模式。
以下各节展示了如何创建和使用WriteModel
类型的每个变体。每个节中的示例使用以下在people
集合中的文档
{ "_id": 1, "name": "Karen Sandoval", "age": 31 } { "_id": 2, "name": "William Chin", "age": 54 } { "_id": 8, "name": "Shayla Ray", "age": 20 }
此数据使用以下Kotlin数据类进行建模
data class Person( val id: Int, val name: String, val age: Int? = null, val location: String? = null )
有关本节中提到的方法和类的更多信息,请参阅以下API文档
插入操作
要执行插入操作,创建一个指定要插入的文档的InsertOneModel
。要插入多个文档,必须为要插入的每个文档创建一个InsertOneModel
。
示例
以下示例创建了一个描述人员的两个文档的InsertOneModel
。
val juneDoc = InsertOneModel(Person(3, "June Carrie", 17)) val kevinDoc = InsertOneModel(Person(4, "Kevin Moss", 22))
重要
当执行bulkWrite()
操作时,InsertOneModel
不能插入一个在集合中已经存在的_id
的文档。在这种情况下,驱动程序会抛出MongoBulkWriteException
。
以下示例尝试插入两个文档,其中_id
的值为1和3。由于集合中已经存在一个_id
为1的文档,操作结果为错误
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={}}].
要了解为什么驱动程序没有插入具有_id
为3的文档,请参阅执行顺序部分。
关于本节中提到的方法和类的更多信息,请参阅 InsertOneModel API 文档。
替换操作
要执行替换操作,创建一个指定要替换的文档的查询过滤器和替换文档的 ReplaceOneModel
。
重要
在执行 bulkWrite()
时,ReplaceOneModel
无法对违反集合上唯一索引约束的更改进行更改。此外,如果查询过滤器没有匹配项,则模型不会执行替换操作。
示例
以下示例创建了一个 ReplaceOneModel
来替换 _id
为 1
的文档,该文档包含额外的 location
字段
val filter = Filters.eq("_id", 1) val insert = Person(1, "Celine Stork", location = "San Diego, CA") val doc = ReplaceOneModel(filter, insert)
关于本节中提到的方法和类的更多信息,请参阅以下资源
ReplaceOneModel API 文档
唯一索引 服务器手册解释
更新操作
要执行更新操作,创建一个指定查询过滤器和更新文档的 UpdateOneModel
或 UpdateManyModel
。
UpdateOneModel
更新与查询过滤器匹配的第一个文档,而 UpdateManyModel
更新与查询过滤器匹配的所有文档。
重要
在执行 bulkWrite()
时,UpdateOneModel
和 UpdateManyModel
类型不能执行违反集合唯一索引约束的更改。此外,如果没有匹配到查询过滤器,这些模型不会执行更新操作。
示例
以下示例创建了一个UpdateOneModel
来增加文档中age
字段1
,该文档的_id
为2
。
val filter = Filters.eq("_id", 2) val update = Updates.inc(Person::age.name, 1) val doc = UpdateOneModel<Person>(filter, update)
关于本节中提到的方法和类的更多信息,请参阅以下资源
UpdateOneModel API 文档
UpdateManyModel API 文档
唯一索引 服务器手册说明
删除操作
要执行删除操作,创建一个指定要删除文档查询过滤器的DeleteOneModel
或DeleteManyModel
。
DeleteOneModel
删除第一个与查询过滤器匹配的文档,而DeleteManyModel
删除所有与查询过滤器匹配的文档。
重要
在执行bulkWrite()
时,如果查询过滤器没有匹配项,则DeleteOneModel
和DeleteManyModel
类型不会删除任何文档。
示例
以下示例创建了一个用于删除_id
为1
的文档的DeleteOneModel
,以及一个用于删除age
值小于30
的文档的DeleteManyModel
。
val deleteId1 = DeleteOneModel<Person>(Filters.eq("_id", 1)) val deleteAgeLt30 = DeleteManyModel<Person>(Filters.lt(Person::age.name, 30))
有关本节中提到的方法和类的更多信息,请参阅以下API文档
执行顺序
默认情况下,bulkWrite()
方法以顺序执行批量操作。这意味着操作将在你将其添加到列表中的顺序执行,直到发生任何错误。
有序执行
bulkWrite()
方法默认按顺序执行批量操作。这意味着操作将按照你将其添加到列表中的顺序执行,直到发生任何错误。
示例
以下示例执行以下批量操作
一个插入操作,其中文档的
name
为"Zaynab Omar"
,且age
为37
一个替换操作,其中文档的
_id
为1
,替换为包含location
字段的文档一个更新操作,其中文档的
_id
为6
,以更改name
字段一个删除操作,删除所有年龄大于
50
的文档
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)
运行此示例后,您的集合包含以下文档
{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" } { "_id": 8, "name": "Shayla Ray", "age": 20 } { "_id": 6, "name": "Zaynab Hassan", "age": 37 }
无序执行
您也可以通过将 false
传递给 BulkWriteOptions
对象上的 ordered()
方法来以任何顺序执行批量操作。这意味着所有写操作都会执行,无论是否有错误。如果发生错误,驱动程序将在最后报告。
以下代码显示了如何执行无序执行的批量操作
val options = BulkWriteOptions().ordered(false) val unorderedResult = collection.bulkWrite(bulkOperations, options)
注意
无序批量操作不保证执行顺序。顺序可能与您列出的顺序不同,以优化运行时间。
在前面的示例中,如果 bulkWrite()
方法在更新操作之后执行插入操作,则更新操作不会产生变化,因为此时文档不存在。集合将包含以下文档
{ "_id": 1, "name": "Sandy Kane", "location": "Helena, MT" } { "_id": 8, "name": "Shayla Ray", "age": 20 } { "_id": 6, "name": "Zaynab Omar", "age": 37 }
有关本节中提到的方法和类的更多信息,请参阅以下API文档
摘要
要执行批量操作,创建一个WriteModel
文档列表并将其传递给bulkWrite()
方法。
WriteModel
有六种变体
InsertOneModel
ReplaceOneModel
UpdateOneModel
UpdateManyModel
DeleteOneModel
DeleteManyModel
有两种方式来执行bulkWrite()
方法
有序,驱动程序将按顺序执行写操作,直到发生任何错误
无序,驱动程序以任何顺序执行所有写操作,并在操作完成后报告任何错误