$size只能匹配数组长度等于某具体数值;要实现大于、小于等条件,必须用$expr配合$size,因$size语法强制要求数字字面量,不支持操作符。

直接用 $size 只能查「长度等于某值」;要查「大于」「小于」或带类型安全的条件,必须用 $expr + $size 组合,$where 已不推荐且多数云服务禁用。
为什么 $size 不能写 {$gt: 2}
$size 是硬性限制操作符,语法只接受数字字面量,不是表达式。写成 {"tags": {"$size": {"$gt": 2}}} 会立刻报错:errmsg: "size operator must be followed by a number"。
常见误用场景:
- 想查「至少 3 个标签」却写了
{"tags": {"$size": {"$gte": 3}}} - 嵌套字段用错路径,比如
{"comments.authors": {"$size": 0}}但实际字段是comments.authorIds - 忽略字段缺失行为:若文档没有
tags字段,或该字段为null/undefined,它不会被匹配(不是返回空数组)
用 $expr 实现「长度大于 N」或「长度在范围内」
$expr 允许你在查询中使用聚合表达式,支持 $size、$gt、$isArray 等,且不执行 JS,性能可控。
正确写法示例:
- 查
tags长度 > 2:{"$expr": {"$gt": [{"$size": "$tags"}, 2]}} - 查
tags长度 ≥ 1 且 ≤ 5:{"$expr": {"$and": [{"$gte": [{"$size": "$tags"}, 1]}, {"$lte": [{"$size": "$tags"}, 5]}]}} - 加类型校验防崩溃:
{"$expr": {"$and": [{"$isArray": "$tags"}, {"$gt": [{"$size": "$tags"}, 2]}]}}
⚠️ 注意:$expr 中所有字段引用必须带 $ 前缀(如 "$tags"),不能写 "tags";否则整个条件静默失效。
替代技巧:用字段存在性模拟「最小长度」
当只需快速判断「至少 N+1 个元素」且不想用 $expr,可用数组索引存在性代替(适用于简单场景):
- 查
tags至少有 3 个元素 → 检查第 2 个位置是否存在:{"tags.2": {"$exists": true}} - 查
tags至少有 1 个元素 →{"tags.0": {"$exists": true}}
这个方法快、可走索引,但有明显限制:
- 无法区分
["a"]和["a", null](后者tags.1存在但值为null) - 不能用于「最大长度」或「精确范围」
- 字段为非数组类型(如字符串)时可能误匹配(
"abc".2合法)
真正上线前必须检查的三件事
数组长度查询容易在生产环境翻车,尤其数据结构不统一时:
- 确认目标字段是否始终为数组类型——用
$isArray显式校验比依赖业务逻辑更可靠 - 评估是否值得建「预计算字段」:比如存一个
tagsCount整数并建索引,比每次算$size快得多 - 避免在大集合上无索引使用
$expr:它无法高效利用复合索引,{tags: 1}索引对$expr中的$size几乎无效











