使用MongoTemplate更新MongoDB三层嵌套数组中指定replies的likes字段
问题原因
你当前的写法问题出在更新路径的位置运算符使用错误:普通的$位置运算符只能匹配第一层满足查询条件的数组元素,面对comments -> replies两层嵌套数组的场景,comments.$[].replies.$.likes中的$只会定位到匹配的comment下replies数组的第一个元素,因此永远操作的是第一个reply的likes数组,无法定位到你指定的replyId对应的元素。
解决方案
使用MongoDB 3.6及以上版本支持的数组筛选标识符(Array Filters)功能,为两层嵌套数组分别定义筛选规则,即可准确定位到指定comment和reply对应的likes数组。
修改后的代码如下:
// 查询条件仅需要定位到对应post文档即可,数组元素的匹配交给arrayFilter处理 Query query = Query.query(Criteria.where("_id").is(new ObjectId(postId))); Update update = new Update(); if (state) { // 移除用户id update.pull("comments.$[comment].replies.$[reply].likes", new ObjectId(userId)); } else { // 新增用户id,使用addToSet避免同一个用户重复点赞插入重复数据 update.addToSet("comments.$[comment].replies.$[reply].likes", new ObjectId(userId)); } // 定义数组筛选规则,和更新路径中的标识符一一对应 update.filterArray(Criteria.where("comment._id").is(new ObjectId(commentId))); update.filterArray(Criteria.where("reply._id").is(new ObjectId(replyId))); mongoTemplate.updateFirst(query, update, MyEntity.class);
补充说明
- 更新路径中的
$[comment]、$[reply]是自定义的筛选标识符,名称和filterArray中定义的筛选条件前缀一一对应即可 - 点赞场景推荐使用
addToSet替代push,可以自动判重,避免同一个用户ID被多次插入到likes数组中,更符合业务逻辑
内容的提问来源于stack exchange,提问作者hanjiman
相关产品推荐
相关产品推荐

