$or用于多字段任意匹配,需以数组形式包裹独立查询对象;注意索引限制、嵌套逻辑需显式用$and/$or,聚合中$or为表达式且不走索引。

用 $or 实现多字段任意匹配
当需要查出“满足条件 A 或条件 B 或条件 C”的文档时,$or 是最直接的写法。它接受一个数组,每个元素是一个独立的查询对象,只要任一对象匹配,整个文档就入选。
常见错误是把多个条件平铺在同一个对象里,比如 { status: "active", type: "user" } —— 这是“与”逻辑,不是“或”。要表达“status 是 active 或 type 是 user”,必须显式用 $or 包裹:
{
$or: [
{ status: "active" },
{ type: "user" }
]
}
- 每个子条件必须是完整对象,不能写成
{ $or: [ { status: "active" }, type: "user" ] }(语法错误) - 子条件内部仍支持嵌套操作符,比如
{ $or: [ { score: { $gt: 80 } }, { tags: { $in: ["vip"] } } ] } - 如果所有子条件都针对同一字段,有时可改用
$in更简洁,例如{ status: { $in: ["active", "pending"] } }等价于$or: [{ status: "active" }, { status: "pending" }]
注意 $or 的索引使用限制
MongoDB 对 $or 的索引优化比较保守:只有当每个子条件中涉及的字段都有独立索引时,$or 才能分别走索引;否则可能全表扫描。
比如这个查询:
{
$or: [
{ email: "a@b.com" },
{ phone: "138****1234" }
]
}
- 若只有
email单字段索引,没有phone索引,则$or很可能不走索引 - 解决方法是为
phone字段也建索引:db.users.createIndex({ phone: 1 }) - 或者合并建复合索引(但注意:复合索引对
$or每个分支的字段顺序不敏感,但必须覆盖全部字段)
嵌套 $or 与 $and 混合时的括号意识
MongoDB 默认按层级解析,不自动加括号。当你想表达“(A 或 B)且 C”,必须手动用 $and 显式包裹,否则会变成 “A 或(B 且 C)”。
错误写法(意图是“status=active 或 (type=user 且 score>90)”):
{
$or: [ { status: "active" }, { type: "user", score: { $gt: 90 } } ]
}
正确写法(意图是“(status=active 或 type=user) 且 score>90”):
{
$and: [
{ score: { $gt: 90 } },
{ $or: [ { status: "active" }, { type: "user" } ] }
]
}
-
$and在顶层可省略(因为 MongoDB 查询对象默认是“与”),但一旦混入$or,逻辑优先级就容易误判 - 建议凡含混合逻辑,一律显式写出
$and和$or,避免靠记忆运算符优先级
聚合管道中使用 $or 的注意事项
在 $match 阶段用 $or 和 find() 里完全一致;但在其他阶段(如 $expr、$cond)里不能直接用 $or,得换用 $or 表达式(注意:名字一样,但用法不同)。
例如在 $expr 中判断两个条件是否至少一个成立:
{
$expr: {
$or: [ { $eq: ["$status", "active"] }, { $gt: ["$score", 85] } ]
}
}
- 这里的
$or是聚合表达式,参数是表达式数组,不是查询对象数组 - 不能在
$expr里写{ $or: [ { status: "active" } ] },会报错 “unknown operator: status” - 聚合中的
$or不走索引,纯内存计算,大数据量慎用
真正容易被忽略的是:同一个 $or 写法,在 find()、$match 和 $expr 里的语义和参数结构完全不同,看错上下文就直接报错。











