$size仅支持精确匹配数组长度,不支持$gt等比较操作;可用$expr+$size实现长度大于n的查询,推荐组合$exists和$type确保字段为有效数组。

用 $size 查询数组长度等于 N 的文档,但不能用于“大于”
$size 只支持精确匹配数组长度,不支持 $gt、$gte 等比较操作。写 { tags: { $size: { $gt: 10 } } } 会直接报错:Operator $gt is not valid for use with $size。
常见误用场景:想查 comments 字段包含超过 10 条评论的文档,却尝试组合 $size 和比较操作符。
-
$size是严格等值匹配,只接受整数参数,例如{ items: { $size: 11 } } - 它无法利用索引优化(即使字段有索引),在大数据集上性能较差
- 对空数组或缺失字段的行为是确定的:缺失字段不匹配,
null值也不匹配
用 $expr + $size 实现数组长度大于 10 的查询
MongoDB 3.6+ 支持在 $expr 中使用聚合表达式,$size 可以嵌套其中,并配合 $gt 判断长度是否超限。
这是目前最推荐的原生方案,语法清晰且能走部分索引(如果字段本身有单字段索引,虽不能加速 $size 计算,但可快速过滤掉不含该字段的文档):
{ $expr: { $gt: [{ $size: "$tags" }, 10] } }
注意点:
- 字段名必须加引号并前置
$,即"$tags",写成tags或"tags"都会报错FieldPath field names may not start with '$' - 如果
tags字段不存在、为null或不是数组,$size返回0或报错(取决于 MongoDB 版本),所以结果可能比预期多或少;建议先用$type过滤:{ tags: { $type: "array" } } - 在聚合管道中使用时,可与
$match组合,但不要放在第一个$match阶段之后再依赖该字段做计算——顺序影响结果
避免用 $where,除非你清楚它的代价
$where 允许写 JavaScript 表达式,比如 { $where: "this.tags && this.tags.length > 10" },但它有严重缺陷:
- 完全无法使用任何索引,全表扫描不可避免
- 每个文档都要启动 JS 引擎执行,CPU 开销大,高并发下容易拖垮 mongod
- 在分片集群中,
$where无法下推到 shard,所有数据会拉到 mongos 再过滤 - 从 MongoDB 4.4 起,
$where默认被禁用(需显式设置security.javascriptEnabled: true),生产环境基本不可用
除非你在本地调试极小集合,或处理一次性迁移脚本,否则别碰 $where。
更健壮的写法:加类型检查 + 处理边缘情况
真实业务中,tags 可能是缺失、null、字符串、对象,甚至嵌套数组。只靠 $size 容易漏判或误判。
推荐组合条件,确保字段存在、是数组、且长度达标:
{
tags: { $exists: true, $type: "array" },
$expr: { $gt: [{ $size: "$tags" }, 10] }
}
如果数组里可能含 null 元素且你想排除它们,就得进聚合管道用 $filter 预处理——这时候已不是简单查询,而是需要 $addFields + $size 配合了。
真正麻烦的不是语法,而是“数组长度”这个需求背后往往隐含语义:是有效标签数?去重后数量?还是原始插入条数?这些都得在应用层或聚合阶段明确定义,数据库只认字面值。











