正确写法是用andoperator封装复合条件再传入oroperator,避免直接将多个字段条件并列传入oroperator导致逻辑错误;需用addcriteria叠加条件,动态拼接时须校验非空;索引设计应匹配$or分支的查询模式。

Criteria 的嵌套组合是关键,不是简单堆砌 andOperator 和 orOperator —— 错误写法会直接导致查询逻辑失效或空结果。
用 orOperator 包裹完整子条件,而不是只包字段值
常见错误是把 orOperator 当成“多个字段 OR”,比如这样写:
criteria.orOperator(
Criteria.where("state1").is(11),
Criteria.where("state2").is(22),
Criteria.where("value").gte(300)
)
这实际等价于 { $or: [ {state1:11}, {state2:22}, {value: {$gte: 300}} ] },即三者任一满足就命中——但你要的是 (state1=11 AND state2=22) OR value>=300。
正确做法是把整个 AND 条件封装成一个 Criteria 实例,再放进 orOperator:
- 先用
andOperator构建复合AND条件:new Criteria().andOperator(Criteria.where("state1").is(11), Criteria.where("state2").is(22)) - 再把这个结果和另一个条件一起传给
orOperator:Criteria.orOperator(andCondition, Criteria.where("value").gte(300)) - 最后加到
Query中:query.addCriteria(orCriteria)
Query 默认是 AND 关系,外层别漏掉 addCriteria
很多人以为 new Query(criteria) 就够了,但混合查询中往往需要叠加其他约束(比如分页、状态过滤),这时必须用 query.addCriteria(...),否则前面构造的 orOperator 会被覆盖。
例如要查“已启用且(满足 OR 条件)”的文档:
- 错:直接
new Query(orCriteria)→ 丢失status: "enabled"条件 - 对:先
Query query = new Query(),再query.addCriteria(Criteria.where("status").is("enabled")),最后query.addCriteria(orCriteria)
注意:多个 addCriteria 之间默认是 AND 关系,所以外层 AND + 内层 OR 的结构就自然成立。
动态拼接时,避免空 Criteria 导致语法错误
实际业务中常根据参数是否为空决定是否加入某条件。如果直接对空集合调用 orOperator,会抛 IllegalArgumentException:“At least two criteria required”。
安全写法是显式判断:
- 收集所有待 OR 的非空条件到
List<criteria></criteria> - 检查 size ≥ 2 才调用
Criteria.orOperator(list.toArray(new Criteria[0])) - 如果只有 1 个条件,直接用
Criteria.where(...);0 个则跳过 - 特别注意:不能把
null或空字符串当有效条件塞进列表
索引对混合查询的影响容易被忽略
$or 子句中的每个分支会单独走索引,但 MongoDB 不会为整个 $or 组合自动选最优索引。比如 { $or: [ {a:1, b:1}, {c:1} ] },即使你建了 {a:1,b:1} 和 {c:1} 两个索引,查询仍可能全表扫描。
优化建议:
- 优先把高频、高选择性的条件放在
$or第一位 - 避免在
$or里混用范围查询(如$gt)和等值查询,前者无法高效利用复合索引前缀 - 用
explain()看执行计划,确认是否用了预期索引
最麻烦的是 AND+OR 嵌套层级深时,索引设计必须贴合查询模式,而不是按字段热度拍脑袋建。











