MongoDB 条件操作符全解析
(MongoDB 8.0+,2025 年最新实践)
核心结论:
条件操作符 = 查询(find)和更新(update)的“逻辑引擎”
所有操作符都以 $ 开头,支持嵌套、数组、正则、地理、逻辑组合
一、条件操作符分类速览
| 分类 | 操作符 | 用途 |
|---|
| 比较 | $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin | 数值、字符串、日期比较 |
| 逻辑 | $and, $or, $not, $nor | 组合多个条件 |
| 元素 | $exists, $type | 判断字段存在或类型 |
| 数组 | $all, $elemMatch, $size | 数组匹配 |
| 评估 | $regex, $text, $mod, $where | 正则、文本、取模、JS 表达式 |
| 地理 | $geoWithin, $near, $geoIntersects | 地理空间查询 |
二、比较操作符(Comparison Operators)
| 操作符 | 等价写法 | 示例 |
|---|
$eq | field: value | { age: { $eq: 30 } } → { age: 30 } |
$ne | 不等于 | { status: { $ne: "active" } } |
$gt | 大于 | { salary: { $gt: 5000 } } |
$gte | 大于等于 | { createdAt: { $gte: new Date("2025-01-01") } } |
$lt | 小于 | { age: { $lt: 25 } } |
$lte | 小于等于 | { score: { $lte: 100 } } |
$in | 在数组中 | { role: { $in: ["admin", "editor"] } } |
$nin | 不在数组中 | { tag: { $nin: ["spam", "ad"] } } |
// 推荐写法(简洁)
db.users.find({ age: 30 }) // $eq
db.users.find({ age: { $gte: 18, $lte: 65 } }) // 范围
db.users.find({ email: { $in: [/gmail\.com$/, /163\.com$/] } }) // 正则数组
三、逻辑操作符(Logical Operators)
| 操作符 | 说明 | 示例 |
|---|
$and | 所有条件都满足 | { $and: [{ age: { $gt: 18 } }, { status: "active" }] } |
$or | 任一条件满足 | { $or: [{ age: { $lt: 13 } }, { age: { $gt: 65 } }] } |
$not | 取反 | { age: { $not: { $gte: 30 } } } |
$nor | 都不满足 | { $nor: [{ status: "banned" }, { role: "admin" }] } |
// 查找 18~65 岁活跃用户
db.users.find({
$and: [
{ age: { $gte: 18 } },
{ age: { $lte: 65 } },
{ status: "active" }
]
})
// 简写:MongoDB 自动隐式 AND
db.users.find({ age: { $gte: 18, $lte: 65 }, status: "active" })
// 查找未激活或已封禁用户
db.users.find({
$or: [
{ status: "inactive" },
{ banned: true }
]
})
四、元素操作符(Element Operators)
| 操作符 | 说明 | 示例 |
|---|
$exists | 字段是否存在 | { phone: { $exists: true } } |
$type | 字段类型 | { age: { $type: "number" } } 或 { age: { $type: 2 } } |
// 查找有地址的用户
db.users.find({ "address": { $exists: true } })
// 查找 age 是数字的用户(排除字符串)
db.users.find({ age: { $type: "number" } })
// 常见类型编号
// 1: double, 2: string, 3: object, 4: array, 8: boolean, 9: date, 10: null, 16: int, 18: long
五、数组操作符(Array Operators)
| 操作符 | 说明 | 示例 |
|---|
$all | 数组包含所有元素 | { tags: { $all: ["tech", "ai"] } } |
$elemMatch | 数组中任一对象满足多条件 | { scores: { $elemMatch: { subject: "math", score: { $gte: 90 } } } } |
$size | 数组长度 | { hobbies: { $size: 3 } } |
// 拥有 JS 和 Python 技能
db.employees.find({ skills: { $all: ["JavaScript", "Python"] } })
// 成绩中数学 ≥90 且英语 ≥85
db.students.find({
scores: {
$elemMatch: {
subject: "math",
score: { $gte: 90 }
}
},
scores: {
$elemMatch: {
subject: "english",
score: { $gte: 85 }
}
}
})
// 爱好正好 3 个
db.users.find({ hobbies: { $size: 3 } })
六、评估操作符(Evaluation Operators)
| 操作符 | 说明 | 示例 |
|---|
$regex | 正则匹配 | { name: { $regex: /^李/, $options: "i" } } |
$text | 全文搜索(需文本索引) | { $text: { $search: "MongoDB" } } |
$mod | 取模 | { age: { $mod: [5, 0] } } → 年龄能被 5 整除 |
$where | JS 表达式(慎用!) | { $where: "this.age > this.children.length * 10" } |
// 姓名以 “张” 开头(忽略大小写)
db.users.find({ name: { $regex: /^张/i } })
// 全文搜索(需先创建索引)
db.articles.createIndex({ title: "text", content: "text" })
db.articles.find({ $text: { $search: "MongoDB 性能" } })
// 年龄是 5 的倍数
db.users.find({ age: { $mod: [5, 0] } })
七、地理空间操作符(Geospatial)
// 创建 2dsphere 索引
db.stores.createIndex({ location: "2dsphere" })
// 查找 10km 内门店
db.stores.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [116.4, 39.9] },
$maxDistance: 10000
}
}
})
// 查找在北京三环内的点
db.stores.find({
location: {
$geoWithin: {
$geometry: {
type: "Polygon",
coordinates: [/* 三环坐标数组 */]
}
}
}
})
八、更新中使用的条件操作符
// 只有当年龄 > 30 才加薪
db.employees.updateMany(
{ age: { $gt: 30 } },
{ $inc: { salary: 1000 } }
)
// 数组中存在 Python 才添加 Go
db.employees.updateMany(
{ skills: "Python" },
{ $addToSet: { skills: "Go" } }
)
九、性能与索引建议
| 操作符 | 是否建议建索引 | 索引类型 |
|---|
$eq, $gt, $lt | 是 | 单字段 / 复合 |
$in | 是(小数组) | 单字段 |
$regex(前缀) | 是 | 单字段 |
$text | 必须 | text 索引 |
$elemMatch | 是 | 复合索引 |
$where | 否(全表扫描) | 避免使用 |
// 推荐索引
db.users.createIndex({ status: 1, age: -1 })
db.users.createIndex({ email: 1 })
db.users.createIndex({ "address.city": 1 })
十、完整条件查询示例脚本
// complex_query.js
use company
print("复杂条件查询示例\n")
// 1. 技术部、30~40岁、会 Python 的活跃员工
const result1 = db.employees.find({
department: "技术部",
age: { $gte: 30, $lte: 40 },
skills: "Python",
status: "active"
})
.sort({ age: -1 })
.limit(5)
.projection({ name: 1, age: 1, skills: 1, _id: 0 })
print("技术部 Python 工程师(30-40岁):")
result1.forEach(printjson)
// 2. 姓名含“李”或邮箱是163,地址存在
const result2 = db.users.find({
$or: [
{ name: { $regex: /李/ } },
{ email: { $regex: /@163\.com$/ } }
],
"address": { $exists: true }
}).count()
print(`\n匹配“李”或163邮箱且有地址的用户:${result2} 人`)
// 3. 爱好正好3个,且包含“阅读”
const result3 = db.users.find({
hobbies: { $size: 3 },
hobbies: "阅读"
}).limit(3)
print("\n爱好正好3个且包含阅读的用户:")
result3.forEach(doc => printjson(doc.hobbies))
运行:
mongosh complex_query.js
十一、一句话总结
“MongoDB 条件操作符 = $ + 逻辑/比较/数组/正则 + 索引 = 强大查询引擎”
快速操作符模板
// 范围查询
{ age: { $gte: 18, $lte: 65 } }
// 数组包含
{ tags: { $all: ["A", "B"] } }
// 正则忽略大小写
{ name: { $regex: /^admin/i } }
// 逻辑组合
{
$and: [
{ status: "active" },
{ $or: [{ role: "admin" }, { role: "editor" }] }
]
}
官方文档:
- https://www.mongodb.com/docs/manual/reference/operator/query/
- https://www.mongodb.com/docs/manual/reference/operator/aggregation/
如需 复杂嵌套条件、正则性能优化、从 SQL WHERE 迁移 或 实时条件订阅(Change Streams),欢迎继续提问!