在MongoDB中,直接用{field1: {$eq: "$field2"}}无效,因顶层查询不支持字段间比较;必须使用{$expr: {$eq: ["$field1", "$field2"]}},且需确保字段存在、类型一致,否则返回false,并引发全表扫描。

用 $eq 在聚合管道中比较两个字段值
直接在查询条件里写 { field1: { $eq: "$field2" } } 是无效的——MongoDB 查询顶层不支持字段间动态比较。$eq 只有在聚合阶段(比如 $match 配合 $expr)才能引用另一个字段。正确姿势是把比较逻辑放进 $expr:
{ $expr: { $eq: ["$a", "$b"] } }
注意两边都必须加 $ 前缀,表示字段路径;不加就是字面量。这个表达式会为每条文档计算 a 和 b 的值是否严格相等(类型+值都一致)。
为什么 find({ a: "$b" }) 不起作用
这是新手最常踩的坑:find({ a: "$b" }) 实际是在查 a 字段值**字面等于字符串 "$b"**,不是取 b 字段的值。MongoDB 查询语法默认把对象值当静态数据,不解析字段引用。只有 $expr 显式启用表达式引擎,才允许跨字段运算。另外,$eq 在 $expr 内部是必需的,不能省略成 { $expr: "$a == $b" }——MongoDB 不支持这种 JS 风格语法。
$cmp 和 $eq 的适用场景差异
如果只是判断相等,$eq 最简洁;但若后续还要处理「大于」「小于」或需要三态结果(-1/0/1),$cmp 更合适:
{ $expr: { $eq: [{ $cmp: ["$a", "$b"] }, 0] } }
不过多一层嵌套就多一分出错可能。特别注意:$cmp 对 null、缺失字段、不同类型(如字符串 vs 数字)的比较有明确定义,而 $eq 在类型不同时直接返回 false,不报错也不隐式转换。
更新操作中字段自比较的写法
想在 updateOne 里基于两字段相等做条件?同样得走 $expr:
db.coll.updateOne(
{ $expr: { $eq: ["$status", "$expectedStatus"] } },
{ $set: { synced: true } }
)
但注意:更新语句中不能在 $set 内部直接用 $eq 比较字段并赋值(比如 { $set: { flag: { $eq: ["$x", "$y"] } } } 是合法的,但属于聚合更新,需用 updateMany + 聚合管道模式)。普通更新只接受静态值或简单字段引用,不支持表达式计算。
字段类型一致性往往比想象中更关键——比如一个存的是字符串 "123",另一个是数字 123,$eq 会直接判为不等,且不会提示类型问题。

















