首页/数据/NoSQL 速查/逻辑操作符 $or / $nor / $not
MongoDB99 条

逻辑操作符 $or / $nor / $not

$or 任一条件成立即命中,$nor 全部条件都不成立才命中,$not 对单个字段表达式取反(常配正则使用)。

NoSQL 速查数据更新于 2026-10-13

三个逻辑操作符的分工

过滤文档里 $or 表示任一条件成立即命中,$nor 表示数组内全部条件都不成立才命中,$not 对单个字段表达式取反(最常用于反转正则)。它们的层不同:$or/$nor 作用在文档层级,$not 只能写在字段内部。设计时只要能把 $or 的等值分支改写成 $in,就应该改写,因为每个 or 分支都可能在计划选择阶段各自试跑候选计划,分支越多规划与执行开销越大。

基本信息

$or数组内任一条件成立即命中
$nor数组内全部条件都不成立才命中
$not对字段级子表达式取反,可包裹正则
限制$not 不能取反整个过滤文档,也不能包裹 $or/$and 这类顶层操作符
适用版本MongoDB 3.6+ 行为一致

示例

示例
// 任一成立:数量小于 2 或者是 VIP
db.orders.find({ $or: [ { qty: { $lt: 2 } }, { vip: true } ] })

// 全部不成立:既不是已取消也不是已退款
db.orders.find({ $nor: [ { status: "canceled" }, { status: "refunded" } ] })

// 取反正则:排除测试与内部账号
db.users.find({ name: { $not: /^test/i } })

// 等价改写:纯等值分支合并成 $in,索引利用率更好
db.orders.find({ status: { $in: ["paid", "shipped"] } })

// 用 explain 对比两种写法的扫描量
db.orders.find({ $or: [ { status: "paid" }, { status: "shipped" } ] }).explain("executionStats")

典型使用场景

  • 复杂备选条件:等值之外还要叠加范围或数组条件时用 $or
  • 排除固定组合:"既不是已取消也不是已退款"用 $nor 比 $not 加 $in 好读
  • 排除测试数据:$not 包正则过滤 test、demo 一类账号
  • 条件分组:把 (A 或 B) 作为与条件之一,与其他字段并列写在顶层
  • 查询改写:分支很多的 $or 拆成多次查询在客户端合并,便于控制每次扫描量

操作符对照

操作符语义适合与不适合
$or数组内任一成立适合混合类型的备选条件;纯枚举优先 $in
$in字段取值在列表内适合单字段枚举,可走索引
$nor数组内全部不成立适合排除固定几种组合
$not字段级取反适合包正则;不能包 $or/$and
$or 的每个分支都可能触发独立的计划选择,分支越多规划开销越大;大量等值分支先合并为 $in,再考虑是否拆查询。
$nor 与 $not 属于否定条件,无法靠自身在索引上定位(索引无法直接表达"不包含"),要用其他可索引条件先把候选集缩小,否则就是全集合扫描。

易错点

  • $not 只能包裹字段级的单个表达式(正则、$gt 等),直接取反整个过滤文档或包裹 $or/$and 会报错
  • $nor 是整体排除语义,写成 $nor 后"取消或退款"与"取消且退款"容易搞混,上线前用小数据集核对命中条数
  • $or 分支写太多会拉高计划选择与合并成本,纯等值枚举应改写成 $in
  • 把 $not 或 $nor 当唯一查询条件会造成全集合扫描,数据量大时先用可索引条件缩小范围

数据来源与参考

  • MongoDB Manual: Logical Query Operators
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌