如何用Spring Data Mongo API实现带条件的findAndModify操作?
正确实现MongoDB findAndModify的Spring Data Mongo Kotlin代码
需求回顾
需要实现与以下MongoDB原生findAndModify等价的Spring Data Mongo逻辑:
db.account_balances.findAndModify({ query: { _id: '1234' }, update: [ { $set: { 'fieldToUpdate': { $cond: { if: { $and: [ { $lte: ['$updatedAt', new ISODate('2024-09-24T00:00:00.000Z')] }, { $lt: [ { $toLong: '$numericalStringField' }, 1000 ] } ], }, then: 15000.0, else: '$fieldToUpdate' } } } } ], new: true })
核心逻辑:根据_id查找文档,仅当文档满足updatedAt ≤ 指定日期且numericalStringField转Long后 < 1000时,将fieldToUpdate设为15000.0,否则保持原字段值,最后返回更新后的文档。
问题分析
之前的代码错误在于将Criteria对象直接传入ConditionalOperators.when,而ConditionalOperators需要使用**聚合表达式(Aggregation Expression)**来构建$cond的判断条件,而非查询用的Criteria。
正确实现代码
import org.springframework.data.mongodb.core.MongoTemplate import org.springframework.data.mongodb.core.findAndModify import org.springframework.data.mongodb.core.query.Criteria import org.springframework.data.mongodb.core.query.Query import org.springframework.data.mongodb.core.query.Update import org.springframework.data.mongodb.core.query.UpdateDefinition import org.springframework.data.mongodb.core.aggregation.ConditionalOperators import org.springframework.data.mongodb.core.aggregation.ComparisonOperators import org.springframework.data.mongodb.core.aggregation.ConvertOperators import org.springframework.data.mongodb.core.query.FindAndModifyOptions // 自定义常量与参数示例 const val COLLECTION_NAME = "account_balances" val targetId = "1234" val eventDate = org.bson.types.DateTime("2024-09-24T00:00:00.000Z") val targetValue = 15000.0 const val FIELD_TO_UPDATE = "fieldToUpdate" const val UPDATED_AT = "updatedAt" const val NUMERICAL_STRING_FIELD = "numericalStringField" fun updateAccountBalance(mongoTemplate: MongoTemplate) { // 构建$cond的判断条件:两个聚合表达式的逻辑与 val updateCondition = ConditionalOperators.and( // 条件1:updatedAt ≤ 指定日期 ComparisonOperators.Lte.valueOf(UPDATED_AT).lessThanEqualToValue(eventDate), // 条件2:numericalStringField转Long后 < 1000 ComparisonOperators.Lt.valueOf( ConvertOperators.ToLong.toLong(NUMERICAL_STRING_FIELD) ).lessThanValue(1000L) ) // 构建$set操作:满足条件则设为targetValue,否则保留原字段值 val update: UpdateDefinition = Update.update( FIELD_TO_UPDATE, ConditionalOperators.`when`(updateCondition) .then(targetValue) .otherwiseValueOf(FIELD_TO_UPDATE) ) // 执行findAndModify val result = mongoTemplate.findAndModify( Query.query(Criteria.where("_id").`is`(targetId)), update, FindAndModifyOptions.options().returnNew(true), // 返回更新后的文档 COLLECTION_NAME ) // 结果处理示例 result?.let { println("更新后的文档:$it") } ?: println("未找到匹配_id的文档") }
关键说明
- 聚合表达式构建条件:用
ConditionalOperators.and组合两个聚合表达式,完全对应MongoDB原生的$and逻辑 - 类型转换与比较:通过
ConvertOperators.ToLong.toLong将字符串字段转为Long类型,再用ComparisonOperators.Lt完成小于比较 - Update构建:直接使用
Update.update传入$cond表达式,替代之前错误的SetOperation用法 - 选项配置:
FindAndModifyOptions设置returnNew(true)对应原生查询的new: true,原生查询未开启upsert,此处也无需配置
内容的提问来源于stack exchange,提问作者Ichroman Raditya Duwila
相关产品推荐
相关产品推荐

