MongoDB 核心语法完全梳理(从基础到高级·完整版)
MongoDB 是最流行的 NoSQL 文档数据库,使用 BSON 格式存储数据,拥有灵活的 Schema 设计和高性能的查询能力。以下是系统性的核心语法梳理。
说明 :本文聚焦于 MongoDB 特有的或核心的语法。通用的 CRUD 概念与关系型数据库类似,不再赘述。
一、MongoDB 核心概念
| SQL 术语 | MongoDB 术语 | 说明 |
|---|---|---|
| Database | Database | 数据库 |
| Table | Collection | 集合(相当于表) |
| Row | Document | 文档(相当于行,BSON 格式) |
| Column | Field | 字段 |
| Index | Index | 索引 |
| JOIN | $lookup / 应用层 Join |
关联查询 |
| Primary Key | _id |
主键(自动生成 ObjectId) |
文档示例:
{
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "张三",
"age": 28,
"email": "zhangsan@example.com",
"address": { "city": "北京", "street": "朝阳路" },
"hobbies": ["阅读", "游泳"]
}
二、数据库与集合操作
2.1 数据库操作
show dbs // 显示所有数据库
use mydb // 创建/切换数据库
db // 查看当前数据库
db.dropDatabase() // 删除当前数据库
2.2 集合操作
db.createCollection("users") // 创建集合
db.createCollection("logs", { capped: true, size: 1048576 }) // 固定集合
show collections // 显示所有集合
db.users.drop() // 删除集合
三、文档插入(Create)
3.1 插入单条/多条
// 插入单条
db.users.insertOne({ name: "张三", age: 28 })
// 插入多条
db.users.insertMany([
{ name: "王五", age: 25 },
{ name: "赵六", age: 30 }
])
// 有序/无序插入
db.users.insertMany([...], { ordered: false }) // false=遇到错误继续插入
四、文档查询(Read)------ 核心
4.1 基础查询与投影
db.users.find({ name: "张三" }) // 条件查询
db.users.find({}, { name: 1, age: 1, _id: 0 }) // 只返回指定字段
db.users.findOne({ name: "张三" }) // 查询单条
4.2 操作符查询
| 类别 | 操作符 | 示例 |
|---|---|---|
| 比较 | $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin |
{ age: { $in: [25, 28] } } |
| 逻辑 | $and, $or, $not, $nor |
{ $or: [{ age: 20 }, { status: "active" }] } |
| 元素 | $exists, $type |
{ email: { $exists: true } } |
| 数组 | $size, $all, $in |
{ tags: { $size: 3 } } |
4.3 高级查询
// 嵌套文档查询
db.users.find({ "address.city": "北京" })
// 正则表达式
db.users.find({ name: /^张/ }) // 开头为"张"
// 数组对象查询($elemMatch)
db.students.find({
grades: { $elemMatch: { subject: "数学", score: { $gt: 80 } } }
})
五、文档更新 (Update)
5.1 更新操作符
| 操作符 | 含义 | 示例 |
|---|---|---|
$set |
设置/更新字段 | { $set: { name: "新名字" } } |
$unset |
删除字段 | { $unset: { temp: "" } } |
$inc |
数值增减 | { $inc: { age: 1 } } |
$mul |
数值相乘 | { $mul: { salary: 1.1 } } |
$rename |
重命名字段 | { $rename: { old: "new" } } |
$push |
数组追加 | { $push: { hobbies: "跑步" } } |
$pop |
数组删除首尾 | { $pop: { hobbies: 1 } } |
$pull |
删除匹配元素 | { $pull: { hobbies: "电视" } } |
5.2 更新方法
// updateOne / updateMany
db.users.updateOne({ name: "张三" }, { $set: { age: 29 } })
db.users.updateMany({ status: "active" }, { $set: { updated_at: new Date() } })
// replaceOne (替换整个文档)
db.users.replaceOne({ name: "张三" }, { name: "张三", age: 30 })
// upsert (不存在则插入)
db.users.updateOne({ name: "李四" }, { $set: { age: 25 } }, { upsert: true })
六、文档删除 (Delete)
db.users.deleteOne({ name: "赵六" }) // 删除一条
db.users.deleteMany({ status: "inactive" }) // 删除多条
db.users.deleteMany({}) // 清空集合
七、查询高级功能(聚合与连接)
7.1 聚合管道 (Aggregation Pipeline)
聚合管道是 MongoDB 最强大的数据分析功能。
基本语法
db.collection.aggregate([
{ $match: { ... } }, // 过滤
{ { $group: { ... } }, // 分组
{ { $sort: { ... } }, // 排序
{ { $project: { ... } }, // 投影
{ $limit: ... }, // 限制
{ $unwind: ... } // 展开数组
])
常用阶段示例
// $group: 分组统计
db.orders.aggregate([
{ $group: {
_id: "$status",
total: { $sum: "$amount" },
avg: { $avg: "$amount" },
count: { $sum: 1 }
}
}
])
// $project: 重塑文档
db.users.aggregate([
{
$project: {
name: 1,
full_name: { $concat: ["$firstName", " ", "$lastName"] },
is_adult: { $gte: ["$age", 18] }
}
}
])
// $unwind: 展开数组
db.articles.aggregate([
{ $unwind: "$comments" }, // 每条评论生成一条记录
{ $group: { _id: "$title", count: { $sum: 1 } } }
])
7.2 连接查询 ($lookup)
$lookup 用于实现类似 SQL 的 JOIN 操作。
基础左连接
db.orders.aggregate([
{
$lookup: {
from: "users", // 关联集合
localField: "userId", // 本集合字段
foreignField: "_id", // 外集合字段
as: "user_info" // 结果存入数组
}
}
])
高级关联(带管道的 $lookup)
支持在关联时进行子查询和条件过滤。
db.orders.aggregate([
{
$lookup: {
from: "users",
let: { uid: "$userId" }, // 定义变量
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$uid"] } } },
{ $project: { name: 1, email: 1 } } // 只返回需要的字段
],
as: "user_info"
}
}
])
八、高级数据处理与多集合输出
MongoDB 在处理"一源多目标"的数据流转时,提供了类似 Oracle INSERT ALL 的机制,以及更强大的聚合输出能力。
8.1 多集合关联查询进阶
除了基础的 $lookup,还可以实现复杂的多字段关联和非等值关联。
8.1.1 多字段复合关联
当外键由多个字段组成时,使用 let 和 pipeline 实现。
// 场景:订单表 orders 有 user_id 和 region_code,需关联 users 表
db.orders.aggregate([
{
$lookup: {
from: "users",
let: { uid: "$userId", rc: "$region_code" },
pipeline: [
{
$match: {
$expr: {
$and: [
{ $eq: ["$_id", "$$uid"] },
{ $eq: ["$region_code", "$$rc"] }
]
}
}
}
],
as: "user_info"
}
}
])
8.1.2 关联后展开与文档合并(模拟 INNER JOIN)
默认 $lookup 返回数组。通过 $unwind 和 $replaceRoot 可以将关联文档"平铺"到主文档中。
db.orders.aggregate([
{ $match: { status: "completed" } },
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user_doc"
}
},
{ $unwind: "$user_doc" }, // 展开数组(一对一关系)
{
$replaceRoot: {
newRoot: { $mergeObjects: [ "$user_doc", "$$ROOT" ] }
}
},
{ $project: { user_doc: 0 } } // 删除冗余字段
])
8.2 结果集拆分与分发(类似 INSERT ALL)
在 ETL 场景中,需要根据条件将数据写入不同的集合。
8.2.1 使用 $out 阶段(覆盖写入)
将聚合结果直接输出到一个新集合(注意:若集合已存在则覆盖)。
// 将活跃用户筛选出来,存入 active_users 集合
db.users.aggregate([
{ $match: { status: "active" } },
{ $project: { name: 1, email: 1 } },
{ $out: "active_users" } // 覆盖写入
])
8.2.2 使用 $merge 阶段(增量合并,推荐)
$merge 比 $out 更灵活,支持 Upsert(更新或插入),且不会删除目标集合中未匹配的旧数据。
// 场景:同步订单状态到历史表
db.orders.aggregate([
{ $match: { status: "completed" } },
{
$merge: {
into: "order_history", // 目标集合
on: "_id", // 匹配主键
whenMatched: "merge", // 匹配时:合并字段(类似 UPDATE)
whenNotMatched: "insert" // 不匹配时:插入新文档
}
}
])
$merge 的高级用法(条件更新/字段操作):
db.orders.aggregate([
{ $match: { status: "cancelled" } },
{
$merge: {
into: "order_archive",
on: "_id",
whenMatched: [
{ $set: { cancelled_at: "$$NOW" } }, // 匹配时设置取消时间
{ $unset: ["temp_field"] } // 同时删除临时字段
],
whenNotMatched: "discard" // 如果历史表没有这条记录,直接丢弃(不插入)
}
}
])
8.3 客户端格式化输出
8.3.1 聚合管道中的格式化
使用 $project 阶段可以完全重排文档结构,甚至重命名字段(支持中文别名)。
db.users.aggregate([
{
$project: {
_id: 0,
"用户ID": "$_id",
"姓名": "$name",
"联系方式": { $ifNull: ["$email", "$phone"] },
"注册年份": { $year: "$created_at" }
}
}
]).pretty()
8.3.2 导出为 CSV/JSON
虽然 MongoDB Shell 不直接支持复杂的 Excel 导出,但可以通过 mongoexport 工具或驱动程序实现。
# 命令行导出 CSV
mongoexport --db=mydb --collection=users --type=csv --fields=name,age,email --out=users.csv
九、索引管理
9.1 索引类型
// 单字段/复合索引
db.users.createIndex({ name: 1 })
db.users.createIndex({ status: 1, age: -1 })
// 唯一索引
db.users.createIndex({ email: 1 }, { unique: true })
// 稀疏索引(只索引有值的文档)
db.users.createIndex({ email: 1 }, { sparse: true })
// TTL 索引(自动过期)
db.sessions.createIndex({ created_at: 1 }, { expireAfterSeconds: 3600 })
// 文本索引
db.articles.createIndex({ title: "text", content: "text" })
9.2 索引管理
db.users.getIndexes() // 查看索引
db.users.dropIndex("name_1") // 删除索引
db.users.hideIndex("name_1") // 隐藏索引(用于测试)
十、事务处理 (4.0+)
MongoDB 支持多文档 ACID 事务(仅限副本集)。
const session = db.getMongo().startSession()
session.startTransaction()
try {
const orders = session.getDatabase("store").orders
const inventory = session.getDatabase("store").inventory
orders.insertOne({ orderId: "001", amount: 100 })
inventory.updateOne({ sku: "A001" }, { $inc: { stock: -1 } })
session.commitTransaction()
} catch (error) {
session.abortTransaction()
} finally {
session.endSession()
}
十一、批量操作
11.1 批量写入
// 混合操作(插入、更新、删除)
const bulk = db.users.initializeOrderedBulkOp()
bulk.insert({ name: "用户A" })
bulk.find({ name: "用户B" }).updateOne({ $set: { age: 25 } })
bulk.find({ status: "inactive" }).remove()
const result = bulk.execute() // 执行批量操作
十二、性能分析与调优
12.1 查询分析
// 查看执行计划
db.users.find({ age: { $gt: 18 } }).explain()
// 详细执行计划(含统计信息)
db.users.find({ age: { $gt: 18 } }).explain("executionStats")
12.2 慢查询日志
db.setProfilingLevel(1, { slowms: 100 }) // 记录超过100ms的查询
db.system.profile.find().pretty() // 查看慢查询
十三、常用命令速查
| 命令 | 说明 |
|---|---|
show dbs |
显示所有数据库 |
use dbname |
切换/创建数据库 |
show collections |
显示当前数据库所有集合 |
db.collection.countDocuments() |
统计文档数(精确) |
db.collection.estimatedDocumentCount() |
估计文档数(快速) |
db.collection.stats() |
查看集合统计信息 |
db.currentOp() |
查看当前操作 |
db.killOp(opid) |
终止操作 |
十四、备份与恢复
# 导出集合(JSON/CSV)
mongoexport --db mydb --collection users --out users.json
mongoexport --db mydb --collection users --type=csv --fields name,age
# 导入集合
mongoimport --db mydb --collection users --file users.json
# 备份整个数据库(二进制)
mongodump --db mydb --out /backup/dir
# 恢复数据库
mongorestore --db mydb /backup/dir/mydb
MongoDB 多表输出方案选型
| 需求场景 | 推荐方案 | 性能 | 复杂度 | 备注 |
|---|---|---|---|---|
| 简单关联查询 | $lookup (基础) |
⭐⭐⭐⭐ | 低 | 适合大多数一对一/多对一场景 |
| 复杂关联/非等值 | $lookup + pipeline |
⭐⭐⭐ | 中 | 灵活度高,支持子查询 |
| ETL 数据归档 | $merge / $out |
⭐⭐⭐⭐⭐ | 中 | 服务端原子操作,比客户端循环快 |
| 跨集合复杂 Join | 客户端手动合并 | ⭐⭐ | 高 | 减少 DB 压力,但增加网络 IO |
| 报表格式化 | 聚合 $project |
⭐⭐⭐⭐ | 低 | 直接在 DB 层清洗数据 |