优先使用 $size 操作符判断数组长度,因其语义明确、性能好、可走索引;$where 性能差、无法用索引、MongoDB 6.0+ 分片集群默认禁用;$expr 仅适用于需动态计算或与其他字段比较的复杂场景。

直接用 $size 就行,$where 和 $expr 都是绕远路,还容易出错。
为什么不用 $where
$where 会把整个文档拉到 JavaScript 引擎里执行,性能差、无法使用索引、MongoDB 6.0+ 在分片集群中默认禁用。哪怕只是想判断数组长度,写成 { $where: "this.tags.length > 3" } 也会触发全表扫描,且不支持 UTF-8 字符串长度的正确计算(比如中文字符被当多个字节算)。
- 它不能利用任何索引,哪怕
tags字段建了索引也白搭 - 在聚合管道里根本不能用
$where - 错误示例:
{ $where: "Array.isArray(this.items) && this.items.length >= 2" }—— 冗余、慢、不可靠
$size 是最直接可靠的方案
$size 是专为数组长度设计的操作符,语义明确、性能好、能走索引(如果字段有单字段索引或复合索引前缀匹配)。
- 查长度等于 3:
{ tags: { $size: 3 } } - 查长度大于 2:
{ tags: { $size: { $gt: 2 } } }—— 注意:这是合法语法,但仅限 MongoDB 5.0+ - 查长度 ≥ 2(兼容所有版本):
{ tags: { $not: { $size: { $lt: 2 } } } }或更稳妥地用聚合 +$expr(见下一条) - 注意:
$size不支持范围比较(如$gt)的老版本会报错,此时必须换聚合
必须用 $expr 的真实场景
只有当你需要「动态计算数组长度并参与其他逻辑」时,才该上 $expr,比如和另一个字段比较、做条件分支、或配合 $substrCP 截取后比长度。
- 查
dataLines长度 > 2 且含两个关键词:{ $and: [ { dataLines: { $regex: "string1" } }, { dataLines: { $regex: "string2" } }, { $expr: { $gt: [ { $size: "$dataLines" }, 2 ] } } ] } - 查数组长度等于某字段值:
{ $expr: { $eq: [ { $size: "$items" }, "$minRequiredCount" ] } } - 聚合中加字段再过滤:
{ $addFields: { tagCount: { $size: "$tags" } } },然后$match: { tagCount: { $gte: 2 } } - ⚠️ 坑:别在
$expr里用$size去查空数组——{ $size: "$tags" }对缺失字段或 null 返回null,不是 0;要防错得先$ifNull
真正容易被忽略的是:数组字段本身可能缺失、为 null,或包含非数组值。生产环境务必用 $type: "array" 先兜底校验,否则 $size 和 $expr 都可能静默失败或返回意外结果。


















