DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
雨云;给项目一台云服务器
RackNerd;$21.99/年 · 1GB KVM

MongoDB 更新报 No array filter found:$[session] 与过滤器名称必须一致

MongoDB 数组更新报 No array filter found 时,对照 $[session] 与过滤器标识符,区分文档查询和数组元素筛选;核对 Spring 原始字段映射、写入范围与追加重试。

Spring Data MongoDB 用 MongoTemplate 给某个会话追加书签,查询条件也能找到文档,却报 No array filter found for identifier 'session' in path 'sessions.$[session].bookmarks'。先对照更新路径里的 session 与 arrayFilters 中的标识符:两者必须是同一个名字。

sessions 是文档里的数组字段名,session 是这次更新为数组元素定义的临时标识符。把过滤条件写成 sessions.sessionId,不等于为 $[session] 定义了过滤器。这类错误发生在更新定义的解释阶段,重新建索引或增加数据库权限不能修正这个名称。

文档查询和数组过滤分别选择不同对象

外层查询决定更新哪份文档,例如同时匹配 _id、tenantId 和 sessions.sessionId。arrayFilters 再决定该文档的哪些数组元素可以被更新,条件从占位符标识符开始。

下面是错误片段示例:

Update update = new Update()
    .push("sessions.$[session].bookmarks", entity)
    .filterArray(Criteria.where("sessions.sessionId").is(sessionId));

更新路径引用的是 session,过滤器却以 sessions 开头。应改为下面的局部结构,假定 entity 已按书签模型校验,sessionId 是目标会话的实际类型和值:

Update update = new Update()
    .push("sessions.$[session].bookmarks", entity)
    .filterArray(Criteria.where("session.sessionId").is(sessionId));

外层 Query 中的 sessions.sessionId 则仍是实际文档路径,不应一起替换成 session.sessionId。标识符要以小写字母开头,且只能包含字母和数字;它不是数组序号,也不必与模型类名相同。

此处使用 Spring Data MongoDB 的 Update.filterArray,当前 API 标明该方法自 2.2 提供。数据库和驱动需支持过滤位置更新;旧依赖不提供相同方法时,先核对受支持版本组合,不能仅因服务器支持就认定调用端也支持。

过滤器中的字段要对照实际 BSON

filterArray 的条件会直接交给驱动,不进一步进行字段名或类型映射。因此模型中 sessionId 如果通过注解存成 sid,数组条件应针对实际保存的 session.sid;不能期待它像普通模型查询一样自动改写。

同样要检查 sessionId 在数据库里是字符串、ObjectId 还是其他类型。名称一致只解决缺少标识符的问题,不会让错误的类型自动匹配。诊断时查看必要字段及生成的更新定义,不输出整份包含用户信息的文档。

$[session] 会作用于所有满足该过滤条件的元素。updateFirst 只限制外层更新文档,并不保证同一文档中只更新一个数组元素。若业务要求一个 sessionId 只对应一个会话,应先确认数据满足该约束;不能把多处追加视为正常。

修正前保留写入范围和重试规则

外层查询继续保留租户、文档身份等必要条件。不要为了让更新“匹配上”移除 tenantId,也不要用空查询对整个集合执行同一追加操作。

$push 会追加数据。请求已经成功却丢失响应时,盲目重试可能产生重复书签;应沿用项目的业务身份和幂等设计。若改用 $addToSet,也要确认它按元素值去重的语义是否符合业务,不能当成按 bookmarkId 自动去重。

这里是在已有文档和数组上更新,不需临时打开 upsert。过滤位置更新在插入分支有额外的数组精确相等条件,不能把创建缺失文档与修正过滤器混成一个操作。

确认目标会话实际发生了变化

在隔离副本中先检查目标存在、目标不存在、标识符拼错、字段映射改变和同一文档出现重复会话 ID 的情况。使用确认写入的结果时,对照匹配数与修改数,再重新读取目标数组,确认只改变预期范围。

错误消失但修改数为零,应继续检查外层文档条件与数组元素条件;计数不足以说明业务成功。成功标准还包括书签内容正确、其他会话未被意外追加,以及失败重试不会制造重复记录。

修改前保存应用代码、依赖版本和需要恢复的目标数据。代码回退不会删除已追加的书签;如需纠正已写入内容,应依据具体业务记录和书签身份处理,避免用整份旧文档覆盖并发产生的新数据。