$filter 是 MongoDB 中唯一能真正“返回筛选后数组”的聚合操作符,必须用于 aggregate() 的 $project、$addFields 或 $set 阶段,需指定 input、as、cond 三要素,不可用于 find() 查询。

直接说结论:$filter 是 MongoDB 中唯一能真正“返回筛选后数组”的聚合操作符,不是简单匹配文档,而是对字段内数组做元素级过滤并保留结构。用错地方(比如在 find() 里)或条件写错,结果会是空数组或原数组不变。
为什么 $filter 不能用在 find() 查询里?
$filter 是聚合管道阶段操作符,只在 aggregate() 中生效。把它塞进 find({ tags: { $filter: ... } }) 会报错 unknown operator: $filter。
- ✅ 正确位置:必须放在
$project、$addFields或$set管道中 - ❌ 常见误用:当成查询条件(类似
$elemMatch)直接写在find()第一个参数里 - ⚠️ 注意:即使你只想查出含特定元素的文档,也该用
$elemMatch或$in;$filter的目标是“改数组内容”,不是“选文档”
$filter 的三个必需字段怎么填?
它必须带 input、cond,推荐显式写 as —— 少一个就语法错误。
-
input:必须是数组字段路径,比如"$tags"或"$items.price";不能是表达式结果(如{ $concat: [...] })除非包裹在$let -
as:变量名(无$),用于cond中引用当前元素,比如"tag",然后在条件里用"$$tag" -
cond:布尔表达式,必须返回true/false;里面不能直接写字符串比较,得用$eq、$gt等操作符
示例:从 tags 数组中筛选出长度大于 3 的字符串
{
$set: {
longTags: {
$filter: {
input: "$tags",
as: "tag",
cond: { $gt: [{ $strLenCP: "$$tag" }, 3] }
}
}
}
}
容易踩坑的类型与空值处理
数组里混了 null、缺失字段、非字符串类型?$filter 默认不报错,但条件可能意外跳过或匹配失败。
- 如果
input字段不存在或为null,结果是null(不是空数组);加$ifNull: ["$tags", []]可兜底 -
cond中对$$item.name取值时,若某个元素没有name字段,$$item.name是null,$eq: ["$$item.name", "a"]返回false—— 这通常符合预期,但要注意和$exists的区别 - 数值比较要小心类型:
"5"和5不相等,$filter不自动转换,得先用$toInt或$toString
最常被忽略的是:你得确认上游阶段已经把目标字段作为数组投射出来了——比如用 $lookup 关联后,结果在 comments 字段里,但没用 $arrayElemAt 或 $map 处理前,它可能是嵌套结构,input 直接写 "$comments" 会因类型不符返回空数组。


















