MongoDB 查询文档完整指南
(MongoDB 8.0+,2025 年最新实践)
核心结论:
查询文档 =find()/findOne()+ 查询条件 + 投影 + 选项
支持嵌套、数组、正则、地理、聚合、索引、实时流
一、核心查询命令
| 命令 | 返回 | 推荐场景 |
|---|---|---|
find(filter, projection) | 游标(Cursor) | 查询多条 |
findOne(filter, projection) | 单个文档 或 null | 查询单条 |
countDocuments(filter) | 数量 | 统计 |
distinct(field, filter) | 去重值数组 | 枚举 |
二、基本查询示例
use company
// 1. 查询所有文档
db.employees.find().pretty()
// 2. 查询技术部员工
db.employees.find({ department: "技术部" }).pretty()
// 3. 查询单个员工(返回第一条)
db.employees.findOne({ name: "张三" })
三、查询操作符大全
| 类型 | 操作符 | 示例 |
|---|---|---|
| 比较 | $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin | { age: { $gte: 30 } } |
| 逻辑 | $and, $or, $not, $nor | { $or: [{ age: 25 }, { name: "李四" }] } |
| 元素 | $exists, $type | { address: { $exists: true } } |
| 数组 | $all, $elemMatch, $size | { skills: { $all: ["JS", "Python"] } } |
| 正则 | $regex | { name: { $regex: /^张/ } } |
| 投影 | 1 / 0 | { name: 1, age: 1, _id: 0 } |
嵌套字段查询
// 查询地址在北京的员工
db.employees.find({ "address.city": "北京" })
// 更新嵌套字段(配合 $set)
db.employees.updateOne(
{ name: "张三" },
{ $set: { "address.zip": "100000" } }
)
数组查询
// 拥有 Python 技能的员工
db.employees.find({ skills: "Python" })
// 同时拥有 JS 和 Python
db.employees.find({ skills: { $all: ["JavaScript", "Python"] } })
// 技能数组长度为 3
db.employees.find({ skills: { $size: 3 } })
// 数组中某个对象满足条件
db.employees.find({
scores: { $elemMatch: { subject: "math", score: { $gte: 90 } } }
})
四、游标操作(Cursor)
const cursor = db.employees.find({ department: "技术部" })
// 1. 遍历
cursor.forEach(doc => printjson(doc))
// 2. 转为数组
const docs = cursor.toArray()
// 3. 分页
cursor.skip(10).limit(5)
// 4. 排序
cursor.sort({ age: -1 }) // 降序
cursor.sort({ age: 1, name: -1 }) // 多字段
// 5. 投影(只返回 name 和 age)
cursor.projection({ name: 1, age: 1, _id: 0 })
五、常用查询方法
| 方法 | 说明 |
|---|---|
.countDocuments(filter) | 精确计数 |
.estimatedDocumentCount() | 快速估计总数(无过滤) |
.distinct("field") | 去重字段值 |
.findOneAndUpdate() | 查询 + 更新 + 返回 |
.aggregate() | 复杂统计 |
// 统计技术部人数
db.employees.countDocuments({ department: "技术部" })
// 获取所有部门(去重)
db.employees.distinct("department")
// 平均年龄
db.employees.aggregate([
{ $group: { _id: null, avgAge: { $avg: "$age" } } }
])
六、高级查询场景
1. 全文搜索(Text Index)
// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })
// 搜索包含 "MongoDB" 的文章
db.articles.find({ $text: { $search: "MongoDB" } })
2. 地理空间查询(2dsphere)
// 创建地理索引
db.stores.createIndex({ location: "2dsphere" })
// 查找附近 5km 的门店
db.stores.find({
location: {
$near: {
$geometry: { type: "Point", coordinates: [116.4, 39.9] },
$maxDistance: 5000
}
}
})
3. 正则表达式
// 姓名以 "李" 开头
db.employees.find({ name: { $regex: /^李/ } })
// 邮箱包含 gmail
db.employees.find({ email: { $regex: /@gmail\.com$/i } })
七、性能优化(索引是关键!)
// 创建索引
db.employees.createIndex({ department: 1 }) // 单字段
db.employees.createIndex({ age: 1, name: -1 }) // 复合索引
db.employees.createIndex({ skills: 1 }) // 数组索引
db.employees.createIndex({ "address.city": 1 }) // 嵌套字段
// 查看执行计划
db.employees.find({ department: "技术部" }).explain("executionStats")
索引原则:
- 查询频繁的字段建索引
- 排序字段建索引
- 复合索引遵循 等值 → 排序 → 范围 顺序
八、实时查询:Change Streams
// 监听 employees 集合的插入和更新
const changeStream = db.employees.watch([
{ $match: { operationType: { $in: ["insert", "update"] } } }
])
for await (const change of changeStream) {
printjson(change.fullDocument)
}
九、GUI 工具查询
| 工具 | 特点 |
|---|---|
| MongoDB Compass | 可视化过滤器、聚合管道构建器 |
| VS Code + MongoDB | 集成 IDE,实时查询 |
| MongoDB Atlas | Web 界面,性能分析 |
十、常见错误与解决方案
| 错误 | 原因 | 解决方案 |
|---|---|---|
Query exceeded time limit | 查询太慢 | 加索引、分页 |
Projection cannot have a mix of inclusion and exclusion | 投影混用 1 和 0 | 除 _id 外不能混用 |
Text index required | 使用 $text 无文本索引 | createIndex({ field: "text" }) |
Cursor not found | 游标超时 | 使用 noCursorTimeout() |
十一、完整查询脚本示例
// query_employees.js
use company
print("员工查询报告\n")
// 1. 技术部 30岁以上员工(分页)
const techSenior = db.employees.find({
department: "技术部",
age: { $gte: 30 }
})
.sort({ age: -1 })
.skip(0)
.limit(10)
.projection({ name: 1, age: 1, skills: 1, _id: 0 })
print("技术部资深员工(前10名):")
techSenior.forEach(printjson)
// 2. 统计各部门人数
print("\n各部门人数统计:")
db.employees.aggregate([
{ $group: { _id: "$department", count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]).forEach(printjson)
// 3. 查找技能包含 Python 的员工
const pythonDev = db.employees.find({ skills: "Python" }).countDocuments()
print(`\n掌握 Python 的员工:${pythonDev} 人`)
// 4. 最近入职的 3 人
print("\n最近入职员工:")
db.employees.find()
.sort({ hireDate: -1 })
.limit(3)
.projection({ name: 1, hireDate: 1, _id: 0 })
.forEach(printjson)
运行:
mongosh query_employees.js
十二、一句话总结
“MongoDB 查询 =
find()+ 条件 + 投影 + 索引 + 聚合”
快速查询模板
// 单条
db.users.findOne({ email: "a@example.com" })
// 多条件
db.posts.find({
status: "published",
tags: { $in: ["tech", "news"] },
createdAt: { $gte: new Date("2025-01-01") }
})
// 分页
db.logs.find().sort({ ts: -1 }).skip(20).limit(10)
// 聚合统计
db.sales.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$product", total: { $sum: "$amount" } } }
])
官方文档:
- https://www.mongodb.com/docs/manual/reference/method/db.collection.find/
- https://www.mongodb.com/docs/manual/tutorial/query-documents/
如需 复杂聚合管道、全文搜索优化、从 SQL SELECT 迁移 或 实时查询订阅,欢迎继续提问!