Spring Data MongoDB中如何单轮询实现Foo文档的Upsert操作?
问题描述
说明:示例基于Kotlin语言的Spring Data MongoDB,使用官方文档中描述的更新方法
请参考以下实体类与仓库代码:
@Document data class Foo( val name: String, val bars: Set<String> = setOf(), @Id val id: String = UUID.randomUUID().toString(), ) @Repository interface FooRepository : CoroutineCrudRepository<Foo, String> { suspend fun saveOrAddBarsFrom(foo: Foo) { if (findAndAddToSetBarsById(foo.id, foo.bars) == 0) { save(foo) } } @Update("{ \$addToSet : { 'bars' : { \$each : ?1 } } }") suspend fun findAndAddToSetBarsById(id: String, bars: Set<String>): Int }
可见saveOrAddBarsFrom实现Foo的Upsert需两次数据库往返:先尝试对已存在Foo执行$addToSet追加字符串到bars集合,未找到则执行save操作。
能否编写方法,通过单次数据库往返实现:Foo不存在则保存,存在则向bars集合追加字符串?
解决方案
可以利用MongoDB的upsert特性,结合Spring Data MongoDB的@Update注解实现单次请求完成Upsert逻辑。核心是用$setOnInsert指定插入时的字段赋值,用$addToSet处理更新时的bars集合追加,同时开启upsert = true:
@Repository interface FooRepository : CoroutineCrudRepository<Foo, String> { @Update( value = "{ \$setOnInsert: { 'name': ?1 }, \$addToSet: { 'bars': { \$each: ?2 } } }", upsert = true ) suspend fun upsertFooById(id: String, name: String, bars: Set<String>): UpdateResult }
逻辑说明
- Foo不存在时:数据库执行插入操作,
$setOnInsert会设置name字段,$addToSet将传入的bars元素添加到新文档中,最终生成的文档完全符合实体类定义。 - Foo已存在时:
$setOnInsert不会执行任何操作,仅$addToSet会把传入的新bars元素追加到已有集合中(自动去重,契合Set的特性)。
使用示例
直接传入对应参数调用即可:
// 基于已有foo实例调用 fooRepository.upsertFooById(foo.id, foo.name, foo.bars)
内容的提问来源于stack exchange,提问作者Matthew Adams
相关产品推荐
相关产品推荐

