$filter 返回空数组却没报错,根本原因是 cond 表达式未用 $$this 显式引用当前遍历项,导致匹配逻辑失效;若 input 字段为 null 或缺失,则直接返回 null 而非空数组。

为什么 $filter 返回空数组却没报错?
常见现象是:明明数组里有匹配的元素,$filter 却返回空数组。根本原因是 cond 表达式写在了错误上下文中——它必须用 $$this(或自定义变量名)显式引用当前遍历项,不能直接写字段名。
比如想筛选 tags 数组中等于 "urgent" 的元素,错误写法:{ cond: { $eq: ["$tags", "urgent"] } };正确写法必须通过 $$this 访问当前元素:
{
$filter: {
input: "$tags",
cond: { $eq: ["$$this", "urgent"] }
}
}
-
input必须是数组表达式(支持嵌套路径如"$comments.author") -
cond内部不能出现$开头的顶层字段引用,否则会被当成文档根字段而非数组元素 - 若数组字段本身为
null或缺失,$filter直接返回null,不是空数组
如何在 $filter 中做多条件判断?
当需要同时满足多个条件(如状态为 active 且分数大于 80),cond 必须用逻辑操作符包裹,不能并列写多个表达式。
例如过滤 users 数组中 status === "active" 且 score > 80 的对象:
{
$filter: {
input: "$users",
cond: {
$and: [
{ $eq: ["$$this.status", "active"] },
{ $gt: ["$$this.score", 80] }
]
}
}
}
- 必须用
$and/$or/$not显式组合,MongoDB 不支持 JavaScript 风格的&&语法 -
$$this是默认变量名,也可用as自定义,如as: "u",然后用$$u.status - 注意字段类型:字符串比较区分大小写,数字比较前确保字段确实是数值类型(避免字符串 "90" 被当作文本比较)
$filter 和 $map 混用时为什么字段访问失效?
典型场景是先过滤再提取字段(如只取匹配用户的邮箱),结果得到 undefined。问题出在 $map 的 in 表达式里仍需用 $$this,但此时 $$this 指的是 $filter 输出的新数组中的每个元素,不是原始文档。
正确链式写法示例(过滤活跃用户后只保留邮箱):
{
$map: {
input: {
$filter: {
input: "$users",
cond: { $eq: ["$$this.status", "active"] }
}
},
in: "$$this.email"
}
}
-
$filter输出仍是数组,所以可直接作为$map的input - 嵌套使用时,每一层的
$$this作用域独立,不会穿透到外层文档 - 如果想在
$filter后做计算(如统计数量),应接$size,而不是误用$map
聚合阶段中 $filter 的性能和兼容性要注意什么?
$filter 本身不触发索引,它只是内存中遍历数组,所以性能取决于数组长度和单次判断开销。大数组(如上万元素)会明显拖慢聚合速度。
- MongoDB 3.2+ 支持
$filter,旧版本需改用$redact或应用层处理 - 数组过大时,考虑是否能在上游用
$unwind+$match替代,这样能利用索引加速筛选 - 如果只是判断“是否存在匹配项”,用
$in或$elemMatch更高效,$filter适合需要返回子集的场景
真正容易被忽略的是:$filter 不改变原字段结构,它只是生成新数组;如果你忘了用 $addFields 或 $project 把结果赋给字段名,后续阶段就用不到这个过滤结果。











