如何简单使用MongoTemplate无需查询实现MongoDB嵌套数组字段更新?
问题解答
可以实现,只要你的MongoDB服务端版本在4.2及以上,Spring Data MongoDB版本在3.0及以上,完全不需要先查询文档,直接单次更新操作就能完成需求。
实现原理
MongoDB 4.2开始支持将聚合管道作为更新操作的参数,我们可以通过$map运算符遍历kosList数组,对每个元素做正则匹配判断:符合条件的元素修改fullPath字段,不符合条件的元素原样返回,最终把处理后的数组替换原数组即可。
原生MongoDB参考语句(无需先查)
db.knowledge_resource_copy1.updateMany( { "kosList.fullPath": /KOS12/ }, [ { $set: { kosList: { $map: { input: "$kosList", as: "kos", in: { $cond: [ { $regexMatch: { input: "$$kos.fullPath", regex: /KOS12/ } }, { $mergeObjects: [ "$$kos", { fullPath: { $concat: [ "testKos", { $substrCP: [ "$$kos.fullPath", 0, 7 ] } ] } } ] }, "$$kos" ] } } } } } ] )
对应MongoTemplate Java代码
依赖导入
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.aggregation.ConditionalOperators; import org.springframework.data.mongodb.core.aggregation.ComparisonOperators; import org.springframework.data.mongodb.core.aggregation.StringOperators; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; import java.util.Arrays; import org.bson.Document;
业务代码
// 构造查询条件,仅匹配存在符合要求元素的文档 Query query = Query.query(Criteria.where("kosList.fullPath").regex("KOS12")); // 构造聚合更新逻辑 Update update = new Update().aggregation(Arrays.asList( set("kosList", map("kosList") .as("kos") .andApply( ConditionalOperators.when( ComparisonOperators.RegexMatch.regex("$$kos.fullPath").regex("KOS12") ) .then( mergeObjectsOf("$$kos") .mergeWith( new Document("fullPath", StringOperators.Concat.valueOf("testKos") .concat(StringOperators.SubstrCP.valueOf("$$kos.fullPath").substring(0, 7)) ) ) ) .otherwiseValueOf("$$kos") ) ) )); // 执行批量更新,不需要先查数据 mongoTemplate.updateMulti(query, update, "knowledge_resource_copy1");
注意事项
- 如果你的
fullPath实际长度不足7位,可自行调整substring的第二个参数,和你原有JS逻辑中的substr行为保持一致 - 低版本的MongoDB或Spring Data MongoDB不支持该特性,需要先升级到对应版本再使用
内容的提问来源于stack exchange,提问作者zhu mo
相关产品推荐
相关产品推荐

