Article

文档数据库MongoDB

更新于:2026-07-16

第一章:MongoDB 基础概念

1.1 什么是 MongoDB

概念名称说明注意事项
MongoDB一个开源的 NoSQL 文档数据库,以 BSON 格式存储数据,支持灵活的模式设计不是关系型数据库,不支持 SQL(原生),但提供类似 SQL 的查询语法
NoSQL”Not Only SQL”,泛指非关系型数据库,强调可扩展性、高性能与灵活数据模型并非完全取代 SQL,而是适用于特定场景(如高并发写入、非结构化数据)
文档数据库以”文档”为基本单位存储数据,通常使用类 JSON 结构文档之间可具有不同字段,无需预定义表结构
MongoDB 适用领域内容管理系统、实时分析、物联网、日志存储、用户配置管理等不适合强事务、复杂多表关联或 ACID 要求极高的金融核心系统

1.2 文档、集合与数据库

概念名称说明注意事项
数据库(Database)顶层容器,用于组织集合;每个 MongoDB 实例可包含多个数据库数据库名区分大小写,不能包含空字符或保留字符(如 / \ . " $
集合(Collection)类似于关系型数据库中的”表”,是文档的容器;无固定 schema集合名不能以 system. 开头(保留用途),且不能包含 $ 字符
文档(Document)MongoDB 中的基本数据单元,采用 BSON 格式,结构为键值对嵌套对象文档必须包含 _id 字段(唯一标识),若未提供则自动生成 ObjectId
_id 字段每个文档的唯一主键,默认为 ObjectId 类型可手动指定 _id,但必须保证在集合内唯一;不可修改
命名空间(Namespace)格式为 database.collection,唯一标识一个集合在内部操作和日志中常以命名空间形式出现

1.3 BSON 与 JSON 的区别

概念名称说明注意事项
JSONJavaScript Object Notation,一种轻量级数据交换格式,人类可读仅支持字符串、数字、布尔、数组、对象、null 六种类型
BSONBinary JSON,MongoDB 使用的二进制编码序列化格式是 JSON 的超集,支持更多数据类型,并优化了存储与遍历效率
BSON 支持的数据类型包括:ObjectId、Date、Binary Data、Timestamp、Decimal128、Int32/64 等在 Shell 中输入 new Date()ObjectId("...") 可创建对应类型
存储效率BSON 为二进制格式,比纯文本 JSON 更紧凑,解析速度更快虽然不可读,但 mongosh 会自动将其显示为可读形式
类型保留JSON 无法区分整数与浮点数(统一为 number),BSON 可明确区分 Int32/64/Double在应用层需注意数值类型的精度问题,避免意外转换

1.4 MongoDB 的核心特性

特性名称说明注意事项
动态 Schema(灵活模式)同一集合中的文档可拥有不同字段结构,无需预先定义表结构提高开发敏捷性,但需在应用层加强数据一致性校验
高性能读写支持内存映射文件、索引优化、批量写入等机制默认写操作不等待磁盘确认(fire-and-forget),可通过 writeConcern 控制可靠性
水平扩展(Sharding)通过分片将数据分布到多个服务器,支持 PB 级数据存储需合理选择分片键,避免热点和数据倾斜
高可用(Replica Set)自动故障转移、数据冗余,主从复制架构至少需要 3 个节点(含仲裁节点)才能实现自动选举
丰富的查询语言支持条件查询、正则匹配、地理空间查询、聚合管道等查询能力接近 SQL,但语法不同,需学习操作符(如 $match$group
原子性操作对单个文档的操作是原子的(包括嵌套字段更新)不支持跨文档事务(4.0+ 支持多文档 ACID 事务,但有性能开销)
GridFS用于存储大文件(>16MB),将文件分块存入两个集合(chunks + files)适用于音视频、日志等大对象存储,但元数据查询较复杂

第二章:MongoDB 安装与环境配置

2.1 在不同操作系统上安装 MongoDB

步骤名称操作细节注意事项
Windows 安装1. 从官网下载 MSI 安装包
2. 运行安装向导,选择”Complete”模式
3. 勾选”Install MongoD as a Service”可自动注册服务
默认安装路径为 C:\Program Files\MongoDB;需手动创建 data\db 目录或指定 --dbpath
macOS 安装(Homebrew)执行命令:
brew tap mongodb/brew
brew install mongodb-community
安装后使用 brew services start mongodb-community 启动服务
Ubuntu/Debian 安装1. 导入公钥:
wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | sudo apt-key add -
2. 添加源并安装:
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
sudo apt update && sudo apt install -y mongodb-org
需根据 Ubuntu 版本(如 jammy、focal)替换 $(lsb_release -cs);安装后默认未启动
CentOS/RHEL 安装类似 Ubuntu,使用 yum/dnf 添加 MongoDB 官方 repo 后安装 mongodb-org需关闭 SELinux 或配置策略,否则可能无法写入数据目录
验证安装执行 mongod --versionmongosh --version 查看版本号若命令未找到,需将 MongoDB 的 bin 目录加入系统 PATH

2.2 启动与连接 MongoDB Shell

步骤名称操作细节注意事项
启动 mongod 服务命令:mongod --dbpath /path/to/data/db(若已配置服务,则用 sudo systemctl start mongod必须确保 --dbpath 指向的目录存在且有读写权限;默认端口 27017
后台运行 mongod添加 --fork --logpath /var/log/mongodb.log 参数--fork 要求必须指定 --logpath,否则启动失败
连接 MongoDB Shell执行命令:mongosh 或指定主机端口:mongosh "mongodb://localhost:27017"若启用了认证,需加 --username--password 参数
切换数据库在 mongosh 中执行:use mydb即使数据库不存在,切换也会成功;只有插入数据后才真正创建
查看当前数据库执行:db.getName()返回当前上下文数据库名
退出 Shell输入:exitquit()不会停止 mongod 服务,仅断开客户端连接

2.3 配置文件与服务管理

配置项/操作说明与语法示例注意事项
配置文件路径默认位置:
- Linux: /etc/mongod.conf
- Windows: 安装目录下的 bin\mongod.cfg
使用 YAML 格式(注意缩进),注释以 # 开头
常用配置参数示例:
yaml<br/>storage:<br/> dbPath: /var/lib/mongodb<br/>net:<br/> port: 27017<br/> bindIp: 127.0.0.1,192.168.1.10<br/>security:<br/> authorization: enabled<br/>
修改 bindIp 可允许远程连接,但需配合防火墙和认证使用
使用配置文件启动命令:mongod -f /etc/mongod.conf若同时指定命令行参数和配置文件,命令行优先级更高
注册为系统服务Ubuntu/Debian:sudo systemctl enable mongod
Windows:安装时勾选服务选项
服务方式启动会自动读取默认配置文件
重载配置MongoDB 不支持动态重载配置,需重启服务生效可通过 db.adminCommand({getParameter: 1, ...}) 查询运行时参数
日志管理配置中设置:
yaml<br/>systemLog:<br/> destination: file<br/> path: /var/log/mongodb/mongod.log<br/> logAppend: true<br/>
日志文件过大时可手动轮转,或使用 logrotate 工具

2.4 常用命令行工具简介(mongosh、mongodump、mongoexport 等)

工具名称用途说明基本语法示例注意事项
mongosh官方交互式 Shell,用于执行数据库操作mongosh "mongodb://user:pass@localhost:27017/mydb"替代旧版 mongo shell,功能更强大,支持语法高亮和自动补全
mongodump备份数据库或集合为 BSON 文件mongodump --db mydb --collection users --out /backup/默认输出到 dump/ 目录;支持 --uri--gzip 等参数
mongorestore从 mongodump 生成的备份恢复数据mongorestore --db newdb /backup/mydb/users.bson若目标集合已存在,默认会插入(不覆盖),可用 --drop 先删除
mongoexport将集合导出为 JSON 或 CSV 格式(适合外部系统交换)mongoexport --db mydb --collection users --type=csv --fields name,email --out users.csv仅支持导出单个集合;嵌套字段需用点号表示(如 address.city
mongoimport从 JSON/CSV 文件导入数据到集合mongoimport --db mydb --collection users --type=csv --headerline --file users.csvCSV 必须包含标题行(除非用 --fields 显式指定);JSON 需每行一个文档(非数组)
bsondump查看 BSON 文件内容(调试用)bsondump dump/mydb/users.bson输出为可读格式,便于验证备份内容
mongostat实时监控 MongoDB 性能指标(类似 top)mongostat --host localhost:27017需对 admin 数据库有权限;显示 insert/update/delete 等操作频率
mongotop查看集合级别的读写耗时mongotop --host localhost:27017按集合统计读写时间(毫秒),帮助定位热点集合

第三章:数据库与集合操作

3.1 创建与切换数据库

操作名称语法 / 命令用途说明注意事项
切换/创建数据库use <database_name>在 mongosh 中切换当前上下文数据库;若数据库不存在,则在首次插入数据时自动创建仅执行 use 不会立即创建数据库,必须插入至少一个文档才会持久化
查看当前数据库db.getName()返回当前 Shell 上下文所处的数据库名db 对象等价,db 即代表当前数据库
列出所有数据库show dbsdb.adminCommand({listDatabases: 1})显示所有非空数据库(或有权限访问的数据库)空数据库(无集合或无数据)默认不显示,需插入数据后才可见
删除当前数据库db.dropDatabase()删除当前上下文数据库及其所有集合和索引需对目标数据库有写权限;操作不可逆
验证数据库是否存在通过 show dbs 查看,或查询 admin.system.databases 集合(需管理员权限)用于脚本中判断数据库是否已创建普通用户通常无法直接访问 system.databases

3.2 创建、查看与删除集合

操作名称语法 / 命令用途说明注意事项
显式创建集合db.createCollection("<collection_name>", { options })手动创建集合,可指定选项(如 capped、size、validator 等)大多数情况下无需显式创建,插入文档时自动创建集合
隐式创建集合db.<collection_name>.insertOne({...})首次向不存在的集合插入文档时自动创建最常用方式,适合动态 schema 场景
查看当前数据库所有集合show collectionsdb.getCollectionNames()列出当前数据库中所有集合名称show collections 更简洁,getCollectionNames() 返回数组便于脚本处理
获取集合对象db.<collection_name>db.getCollection("<collection_name>")返回集合的引用对象,用于后续操作若集合名含特殊字符(如 -),必须使用 getCollection()
删除集合db.<collection_name>.drop()删除整个集合及其索引、数据返回 true 表示成功,false 表示集合不存在;操作不可逆

3.3 集合选项与 capped 集合

选项/概念名称语法 / 说明用途说明注意事项
capped 集合db.createCollection("logs", { capped: true, size: 100000, max: 5000 })固定大小的循环集合,适用于日志、事件流等场景一旦创建,不能转为普通集合;size(字节)必填,max(文档数)可选
size(字节限制)size: <number>指定 capped 集合的最大存储空间(单位:字节)实际分配可能略大于指定值;必须足够容纳至少一个文档
max(文档数量上限)max: <number>限制 capped 集合最多包含的文档数量若同时设置 sizemax,以先达到者为准
validator(文档验证)validator: { $jsonSchema: { ... } }{ field: { $type: "string" } }在插入/更新时校验文档结构仅对新写入生效,不影响已有数据;验证失败会抛出错误
validationLevelvalidationLevel: "strict"(默认)或 "moderate"控制验证严格程度"moderate" 允许修改已有不符合规则的文档
validationActionvalidationAction: "error"(默认)或 "warn"验证失败时的行为"warn" 仅记录日志但允许写入(不推荐生产使用)
usePowerOf2Sizes(已弃用)旧版本用于优化存储分配MongoDB 3.0+ 已移除该选项无需使用

3.4 命名规范与限制

命名对象规范与限制说明注意事项
数据库名不能为空
不能包含 / \ . " $ 空格等字符
区分大小写
长度 ≤ 64 字节
例如:myApp_db 合法,my.dbmy$db 非法Windows 文件系统对大小写不敏感,但 MongoDB 仍视为不同数据库
集合名不能以 system. 开头(保留)
不能包含 $(驱动可能允许,但不推荐)
不能为空
区分大小写
例如:user_profiles 合法,$cmd 是内部命令集合,system.users 用于用户管理虽然某些驱动支持 $,但 Shell 和工具链可能出错
字段名(文档内)不能包含 .(点号)和 $(美元符)作为字段名开头
_id 为保留字段
例如:user.name 是嵌套字段合法,但字段名本身不能是 "user.name"可通过 $rename 修改非法字段名(若已存在),但应避免创建
特殊集合名oplog.rssystem.indexessystem.profileMongoDB 内部使用,用户不应手动操作直接修改可能导致数据库异常
命名建议使用小写字母、下划线分隔(snake_case),语义清晰如:order_itemsuser_sessions避免使用复数形式争议(如 user vs users),团队统一即可

第四章:文档 CRUD 操作

4.1 插入文档(insertOne / insertMany)

方法名称语法用途说明代码示例注意事项
insertOnedb.collection.insertOne(document, options?)插入单个文档db.users.insertOne({ name: "Alice", age: 30 })若未提供 _id,自动生成 ObjectId;若提供重复 _id,抛出错误
insertManydb.collection.insertMany([doc1, doc2, ...], options?)批量插入多个文档db.users.insertMany([{ name: "Bob" }, { name: "Carol" }])默认按顺序插入,遇到错误则停止(ordered: true);可设 ordered: false 继续执行
ordered 选项{ ordered: true | false }控制批量插入是否有序db.users.insertMany([...], { ordered: false })false 可提高吞吐,但错误文档位置不确定;部分成功时返回 insertedIdswriteErrors
writeConcern{ writeConcern: { w: <value>, j: <bool>, wtimeout: <ms> } }控制写操作确认级别db.users.insertOne({...}, { writeConcern: { w: "majority" } })w: 1(默认)表示主节点确认;w: "majority" 表示多数副本确认;j: true 要求写入日志

4.2 查询文档(find / findOne)

方法名称语法用途说明代码示例注意事项
finddb.collection.find(query?, projection?)返回匹配文档的游标(可链式调用 sort/limit 等)db.users.find({ age: { $gt: 25 } }, { name: 1, _id: 0 })不加 .toArray() 在 Shell 中自动打印前 20 条;结果为游标,非数组
findOnedb.collection.findOne(query?, projection?)返回第一个匹配文档(或 null)db.users.findOne({ name: "Alice" })直接返回对象,无需遍历;适合唯一查询(如通过 _id
查询条件{ field: value } 或使用操作符 { field: { $op: value } }指定筛选条件db.users.find({ status: "active", age: { $gte: 18 } })多条件默认为 $and;空查询 {} 返回全部文档
投影(Projection){ field1: 1, field2: 0 }控制返回字段(1 包含,0 排除)db.users.find({}, { name: 1, email: 1, _id: 0 })_id 默认包含,需显式设为 0 才排除;不能混用 0 和 1(除 _id 外)
游标操作.sort(), .skip(), .limit(), .count()对查询结果进一步处理db.users.find().sort({ age: -1 }).limit(10)链式调用顺序影响性能,建议先 filter 再 sort/limit

4.3 更新文档(updateOne / updateMany / replaceOne)

方法名称语法用途说明代码示例注意事项
updateOnedb.collection.updateOne(filter, update, options?)更新第一个匹配文档db.users.updateOne({ name: "Alice" }, { $set: { age: 31 } })必须使用更新操作符(如 $set$inc),否则报错
updateManydb.collection.updateMany(filter, update, options?)更新所有匹配文档db.users.updateMany({ status: "inactive" }, { $set: { archived: true } })同上,必须使用更新操作符
replaceOnedb.collection.replaceOne(filter, replacement, options?)完全替换第一个匹配文档(不保留原结构)db.users.replaceOne({ _id: ObjectId("...") }, { name: "New", role: "admin" })替换文档不能包含 _id 字段(除非与原值相同)
upsert 选项{ upsert: true }若无匹配文档,则插入新文档db.users.updateOne({ email: "x@y.com" }, { $set: {...} }, { upsert: true })插入时 _id 自动生成;常用于”存在则更新,否则创建”场景
返回结果方法返回对象包含 matchedCountmodifiedCountupsertedId判断操作影响范围result.modifiedCount === 0 表示无变更modifiedCount 仅统计实际修改的文档(值未变则不计)

4.4 删除文档(deleteOne / deleteMany)

方法名称语法用途说明代码示例注意事项
deleteOnedb.collection.deleteOne(filter, options?)删除第一个匹配文档db.users.deleteOne({ name: "Alice" })即使有多个匹配,也只删一条;无匹配则不报错
deleteManydb.collection.deleteMany(filter, options?)删除所有匹配文档db.users.deleteMany({ status: "deleted" })慎用空条件 {},会清空整个集合
返回结果返回对象含 deletedCount获取删除文档数量if (result.deletedCount > 0) print("Deleted")无法恢复,操作不可逆
安全删除建议先用 find 验证条件,再执行 delete避免误删db.users.find({ status: "test" });
db.users.deleteMany({ status: "test" })
生产环境建议开启认证并限制删除权限

第五章:查询进阶

5.1 查询条件操作符($eq$gt$in$regex 等)

操作符名称语法示例用途说明代码示例注意事项
$eq{ field: { $eq: value } }等于(通常可省略,直接写 { field: value }db.users.find({ age: { $eq: 30 } })$eq 主要用于与 $not 或聚合中明确表达相等
$ne{ field: { $ne: value } }不等于db.users.find({ status: { $ne: "inactive" } })匹配字段不存在的文档(除非使用 $exists: true 限制)
$gt / $gte{ field: { $gt: value } }大于 / 大于等于db.products.find({ price: { $gte: 100 } })支持数字、日期、字符串(按字典序)比较
$lt / $lte{ field: { $lt: value } }小于 / 小于等于db.events.find({ date: { $lt: new Date("2025-01-01") } })日期需用 new Date() 构造
$in{ field: { $in: [val1, val2, ...] } }字段值在指定数组中db.users.find({ role: { $in: ["admin", "moderator"] } })数组元素类型需一致;支持 ObjectId、字符串等
$nin{ field: { $nin: [val1, val2, ...] } }字段值不在指定数组中db.users.find({ status: { $nin: ["banned", "deleted"] } })同样匹配字段不存在的文档
$regex{ field: { $regex: /pattern/, $options: "i" } }正则匹配db.users.find({ name: { $regex: /^A/i } })支持选项:i(忽略大小写)、m(多行)、x(扩展);性能较低,慎用于大集合
$exists{ field: { $exists: true | false } }判断字段是否存在db.users.find({ email: { $exists: true } })常与 $ne: null 区分:null 字段存在但值为 null
$type{ field: { $type: "string" } }按 BSON 类型筛选db.logs.find({ message: { $type: "string" } })可用字符串(如 "int", "date")或数字代码(如 2 表示 string)
$size{ arrayField: { $size: 3 } }匹配数组长度db.orders.find({ items: { $size: 2 } })无法使用范围(如 $gt: 2),仅精确匹配

5.2 逻辑操作符($and$or$not$nor

操作符名称语法示例用途说明代码示例注意事项
$and{ $and: [ {expr1}, {expr2}, ... ] }所有条件同时成立(默认行为)db.users.find({ $and: [ { age: { $gte: 18 } }, { status: "active" } ] })通常可省略,直接写多个条件;仅当同一字段需多个条件时必须显式使用
$or{ $or: [ {expr1}, {expr2}, ... ] }任一条件成立db.users.find({ $or: [ { role: "admin" }, { vip: true } ] })可与索引结合,但可能降低效率
$not{ field: { $not: { $gt: 100 } } }取反单个条件db.products.find({ price: { $not: { $gt: 500 } } })不能直接用于整个表达式,需作用于具体操作符
$nor{ $nor: [ {expr1}, {expr2}, ... ] }所有条件都不成立db.users.find({ $nor: [ { banned: true }, { deleted: true } ] })等价于 $not + $or;匹配字段缺失的文档

5.3 数组查询与嵌套文档查询

查询类型语法示例用途说明代码示例注意事项
数组元素匹配{ tags: "mongodb" }数组包含指定值db.articles.find({ tags: "tutorial" })自动遍历数组元素,无需 $elemMatch(单条件时)
$elemMatch{ scores: { $elemMatch: { $gt: 80, $lt: 90 } } }数组中至少一个元素满足多个条件db.students.find({ exams: { $elemMatch: { subject: "math", score: { $gte: 90 } } } })多条件作用于同一数组元素时必须使用
数组位置查询{ "comments.0.author": "Alice" }查询数组特定位置的嵌套字段db.posts.find({ "comments.0.rating": { $gte: 4 } })位置索引从 0 开始;若数组长度不足则不匹配
嵌套文档完全匹配{ address: { street: "Main", city: "NYC" } }整个嵌套对象完全相等db.users.find({ contact: { email: "a@b.com", phone: "123" } })字段顺序和数量必须完全一致
嵌套字段查询{ "address.city": "NYC" }查询嵌套文档中的字段db.users.find({ "profile.age": { $gte: 25 } })使用点号表示路径;支持任意深度

5.4 投影(Projection)与字段筛选

投影方式语法示例用途说明代码示例注意事项
包含字段{ field1: 1, field2: 1 }仅返回指定字段db.users.find({}, { name: 1, email: 1 })_id 默认包含,需显式设 _id: 0 排除
排除字段{ field1: 0, field2: 0 }返回除指定字段外的所有字段db.users.find({}, { password: 0, ssn: 0 })不能与包含字段混用(除 _id 外)
数组投影($slice{ comments: { $slice: 5 } }限制返回数组的前 N 个元素db.posts.find({}, { comments: { $slice: -3 } })$slice: [skip, limit] 支持跳过+限制
条件投影($elemMatch{ scores: { $elemMatch: { subject: "math" } } }仅返回数组中匹配的第一个元素db.students.find({}, { scores: { $elemMatch: { grade: { $gte: 90 } } } })用于简化数组内容,避免返回整个数组
投影表达式(聚合风格)仅在聚合管道 $project 中支持高级字段计算与重命名见第七章聚合操作普通 find 不支持表达式(如 $toUpper

5.5 排序、跳过与限制(sort / skip / limit)

方法名称语法示例用途说明代码示例注意事项
sort.sort({ field: 1 | -1 })按字段升序(1)或降序(-1)排序db.users.find().sort({ age: -1, name: 1 })多字段排序按顺序生效;无索引时大数据集性能差
skip.skip(n)跳过前 n 条结果(用于分页)db.products.find().skip(20).limit(10)skip 值越大性能越差,建议配合唯一排序字段优化
limit.limit(n)限制返回最多 n 条文档db.logs.find().sort({ ts: -1 }).limit(100)常用于”最新 N 条”场景
组合使用.sort(...).skip(...).limit(...)实现分页查询db.orders.find({ userId: "..." }).sort({ createdAt: -1 }).skip(0).limit(10)建议始终先 sort 再 skip/limit,确保结果稳定
内存限制sort/skip/limit 在内存中处理若结果集 > 32MB,操作失败大数据分页建议使用游标或基于 _id 的范围查询

第六章:索引与性能优化

6.1 创建与管理索引(createIndex / getIndexes / dropIndex)

方法名称语法用途说明代码示例注意事项
createIndexdb.collection.createIndex(keys, options?)在集合上创建单字段或多字段索引db.users.createIndex({ email: 1 })默认升序(1),降序用 -1;重复创建相同索引无副作用
getIndexesdb.collection.getIndexes()获取集合所有索引信息db.products.getindexes()返回数组,包含 _id_ 索引及用户定义索引
dropIndexdb.collection.dropIndex(indexName | keys)删除指定索引db.users.dropIndex("email_1")db.users.dropIndex({ email: 1 })不能删除 _id_ 索引;删除后查询性能可能下降
dropIndexesdb.collection.dropIndexes()删除集合除 _id 外的所有索引db.logs.dropIndexes()慎用,通常用于重建索引前清理
listIndexesdb.collection.listIndexes()返回索引游标(可用于聚合管道)db.users.listIndexes().toArray()getIndexes() 功能类似,但返回游标
background 选项{ background: true }后台创建索引,不阻塞读写db.orders.createIndex({ status: 1 }, { background: true })推荐在生产环境使用,避免服务中断;创建速度较慢

6.2 唯一索引、复合索引与多键索引

索引类型语法示例用途说明代码示例注意事项
唯一索引db.collection.createIndex({ field: 1 }, { unique: true })确保字段值唯一(包括 null)db.users.createIndex({ username: 1 }, { unique: true })若已有重复值,创建失败;多个 null 被视为重复(除非使用 sparse)
sparse 选项{ sparse: true }仅对存在该字段的文档建索引db.users.createIndex({ email: 1 }, { sparse: true, unique: true })允许多个文档缺失该字段(即多个”null”不冲突)
复合索引db.collection.createIndex({ field1: 1, field2: -1 })支持多字段组合查询db.orders.createIndex({ userId: 1, createdAt: -1 })字段顺序影响查询效率;最左前缀原则适用
多键索引(Multikey)对包含数组的字段自动创建支持数组元素查询db.posts.createIndex({ tags: 1 })自动识别;一个索引最多一个数组字段;不能作为分片键
文本索引db.collection.createIndex({ content: "text" })支持全文搜索db.articles.createIndex({ title: "text", body: "text" })一个集合只能有一个文本索引(可跨多字段);不支持排序
地理空间索引db.collection.createIndex({ location: "2dsphere" })支持地理查询(如附近地点)db.places.createIndex({ geo: "2dsphere" })需字段为 GeoJSON 或 [lon, lat] 格式

6.3 索引使用分析(explain)

方法/选项语法用途说明代码示例注意事项
explain()db.collection.find(...).explain("executionStats")分析查询执行计划与性能db.users.find({ email: "a@b.com" }).explain("executionStats")模式:"queryPlanner"(默认)、"executionStats""allPlansExecution"
winningPlan返回结果中的 queryPlanner.winningPlan显示实际选择的执行计划查看是否使用了索引(IXSCAN)或全表扫描(COLLSCAN)COLLSCAN 表示未命中索引,需优化
totalDocsExaminedexecutionStats.totalDocsExamined扫描文档总数值远大于返回文档数(nReturned)表示效率低理想情况:totalDocsExamined ≈ nReturned
totalKeysExaminedexecutionStats.totalKeysExamined扫描索引条目数若 >0 且 nReturned 小,说明索引有效0 表示未使用索引
stagewinningPlan.stage执行阶段类型(如 COLLSCAN, IXSCAN, FETCH)IXSCAN 表示索引扫描,FETCH 表示回表多阶段组合反映完整流程
indexBoundswinningPlan.inputStage.indexBounds显示索引扫描范围{ "email": [ "[\"a@b.com\", \"a@b.com\"]" ] }范围越精确,效率越高

6.4 覆盖查询与性能调优建议

优化策略说明示例场景注意事项
覆盖查询(Covered Query)查询字段和投影字段均在索引中,无需回表读取文档索引:{ status: 1, updatedAt: -1 }
查询:find({ status: "active" }, { _id: 0, updatedAt: 1 })
必须排除 _id(因不在索引中);显著提升性能
最左前缀原则复合索引仅支持从左开始的连续字段查询索引 (a, b, c) 支持 (a), (a,b), (a,b,c),但不支持 (b)(a,c)设计索引时将高选择性字段放左侧
避免索引过多每个索引占用存储并降低写入性能写密集型集合(如日志)应限制索引数量一般建议 ≤5 个索引/集合
使用 hint() 强制索引find(...).hint({ indexField: 1 })测试不同索引效果或绕过查询优化器误判生产环境慎用,可能随数据分布变化失效
监控慢查询开启 profiler:
db.setProfilingLevel(1, { slowms: 100 })
记录执行时间 >100ms 的查询到 system.profile定期分析慢查询日志,针对性优化
避免正则前导通配符{ name: { $regex: "^Ali" } } 可用索引,{ name: { $regex: "li$" } } 不可用优先使用前缀匹配后缀或中缀正则无法使用索引,考虑文本索引或应用层处理
合理使用 sort + limit先筛选再排序,避免大结果集排序find({ active: true }).sort({ ts: -1 }).limit(10)若无索引支持 sort,内存可能溢出(>32MB 报错)

第七章:聚合操作(Aggregation Pipeline)

7.1 聚合管道基本结构

概念名称说明语法示例注意事项
聚合管道(Pipeline)由多个”阶段(stage)“组成的处理流程,每个阶段对文档流进行转换或筛选db.collection.aggregate([ { $match: {...} }, { $group: {...} } ])阶段按顺序执行,前一阶段输出作为后一阶段输入
阶段(Stage)管道中的单个操作单元,以 $ 开头{ $sort: { age: -1 } }每个阶段可出现多次(如多次 $match
输入文档流聚合从集合中所有文档(或通过 $collStats 等特殊输入)开始默认为集合全部文档可通过 $match 尽早过滤以提升性能
输出结果返回游标(Shell 中自动展开),或通过 $out / $merge 写入集合db.orders.aggregate([...]).toArray()结果不修改原集合(除非使用 $out
错误处理任一阶段出错,整个聚合失败如字段类型不匹配、内存超限等使用 allowDiskUse: true 可缓解内存限制

7.2 常用阶段操作($match$group$project$sort$lookup 等)

阶段名称语法示例用途说明代码示例注意事项
$match{ $match: { <query> } }过滤文档(类似 find){ $match: { status: "completed" } }应尽早使用以减少后续处理数据量
$group{ $group: { _id: <expr>, field: { <accumulator> } } }按字段分组并聚合计算{ $group: { _id: "$category", total: { $sum: "$price" } } }_id 为分组键,可为 null(全局聚合)
$project{ $project: { <field>: <1 | 0 | expr> } }控制输出字段(包含/排除/重命名/计算){ $project: { name: 1, fullName: { $concat: ["$first", " ", "$last"] } } }支持表达式;不能混用 0 和 1(除 _id
$sort{ $sort: { field: 1 | -1 } }对文档排序{ $sort: { totalSales: -1 } }大结果集需索引支持,否则内存可能溢出
$lookup{ $lookup: { from: "otherColl", localField: "fk", foreignField: "_id", as: "joined" } }左外连接其他集合{ $lookup: { from: "users", localField: "userId", foreignField: "_id", as: "user" } }as 字段为数组;性能较低,慎用于大集合
$unwind{ $unwind: "$arrayField" }{ $unwind: { path: "$tags", preserveNullAndEmptyArrays: true } }展开数组,每元素生成一行文档{ $unwind: "$items" }默认跳过 null/空数组;可用选项保留
$limit{ $limit: <number> }限制输出文档数量{ $limit: 10 }常用于分页或取 Top N
$skip{ $skip: <number> }跳过指定数量文档{ $skip: 20 }通常配合 $limit 实现分页
$addFields{ $addFields: { newField: <expr> } }添加新字段(不删除原字段){ $addFields: { isAdult: { $gte: ["$age", 18] } } }等价于 $project 包含所有原字段 + 新字段

7.3 表达式与累加器($sum$avg$push 等)

类型名称语法示例用途说明代码示例(在 $group 中)注意事项
累加器$sum{ $sum: <expression> }求和totalQty: { $sum: "$quantity" }忽略非数字值;$sum: 1 可计数
累加器$avg{ $avg: <expression> }平均值avgPrice: { $avg: "$price" }自动忽略 null/非数字
累加器$push{ $push: <expression> }收集字段值到数组emails: { $push: "$email" }保留重复值;若字段缺失则 push null
累加器$addToSet{ $addToSet: <expression> }收集唯一值到数组tags: { $addToSet: "$tag" }自动去重
累加器$first / $last{ $first: <field> }取分组中第一个/最后一个值firstLogin: { $first: "$loginTime" }依赖 $sort 顺序;无排序时不确定
表达式$cond{ $cond: { if: <bool>, then: <val>, else: <val> } }条件判断statusText: { $cond: { if: { $eq: ["$active", true] }, then: "Active", else: "Inactive" } }可嵌套
表达式$dateToString{ $dateToString: { format: "%Y-%m-%d", date: "$ts" } }日期格式化day: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } }需指定时区(timezone)避免偏差
表达式$substr{ $substr: [ <string>, <start>, <length> ] }截取字符串initials: { $substr: ["$name", 0, 1] }起始位置从 0 开始

7.4 聚合性能与内存限制

优化项/限制说明应对措施注意事项
内存限制(100MB)单个聚合阶段(如 $sort$group)内存使用超过 100MB 会报错添加 { allowDiskUse: true } 选项允许使用临时磁盘文件仅 mongod 支持;mongosh 需显式传递选项:db.coll.aggregate([...], { allowDiskUse: true })
管道优化MongoDB 自动优化管道(如合并 $match、提前过滤)无需手动干预,但应将 $match$project 放在前面可通过 explain() 查看优化后的 pipeline
索引利用$match$sort 阶段可使用索引为常用查询字段创建复合索引$lookup$unwind 无法使用索引
避免大型 $group对全集分组且无筛选会导致高内存消耗$match 缩小范围,或使用 $limit分页聚合建议基于 _id 范围查询而非 skip
$lookup 性能每个文档都会触发一次子查询,N+1 问题被连接集合需有索引(foreignField);考虑应用层 join 或冗余设计不适用于高频实时查询
结果大小限制单个文档 ≤16MB;整个结果集受连接超时和内存限制使用 $limit 控制输出;大数据导出用 $out 写入集合$out 会替换目标集合,$merge 可增量写入(4.2+)
监控聚合性能使用 explain("executionStats") 分析聚合计划关注 usedDiskspills(磁盘溢出次数)频繁 spill 表示需优化或增加内存

第八章:数据导入导出与备份恢复

8.1 使用 mongoimport / mongoexport

工具/操作语法示例用途说明代码示例注意事项
mongoimportmongoimport --db=<db> --collection=<coll> --file=<file> [options]从 JSON/CSV/TSV 文件导入数据到集合mongoimport --db sales --collection orders --type=csv --headerline --file orders.csvCSV 必须有标题行(或用 --fields 指定);JSON 需每行一个文档(非数组)
--type--type=json | csv | tsv指定输入文件格式--type=csv默认为 JSON;TSV 用制表符分隔
--headerline--headerlineCSV 第一行作为字段名mongoimport ... --headerline若无标题行,必须用 --fields "name,age,email" 显式指定
--jsonArray--jsonArray导入包含整个 JSON 数组的文件mongoimport --file data.json --jsonArray文件内容如 [{"a":1}, {"b":2}];性能低于逐行 JSON
mongoexportmongoexport --db=<db> --collection=<coll> [options] --out=<file>将集合导出为 JSON 或 CSVmongoexport --db users --collection profiles --type=csv --fields name,email --out profiles.csv仅支持单集合导出;嵌套字段用点号表示(如 address.city
--query--query='{ "status": "active" }'导出满足条件的文档mongoexport --collection logs --query='{ "level": "error" }' --out errors.json查询语法同 find;需转义引号(Shell 中用单引号包裹)
--limit / --skip--limit=1000 --skip=500控制导出数量与偏移用于分批导出大集合不保证顺序,建议配合 --sort

8.2 使用 mongodump / mongorestore

工具/操作语法示例用途说明代码示例注意事项
mongodumpmongodump --db=<db> --collection=<coll> --out=<dir>备份数据库或集合作为 BSON 文件mongodump --db inventory --out /backup/2025-02-01/默认输出到 dump/ 目录;保留所有类型(包括 Date、ObjectId)
--uri--uri="mongodb://user:pass@host:port/db"指定连接字符串mongodump --uri="mongodb://localhost:27017/sales"支持认证、副本集、SSL 等高级连接
--gzip--gzip压缩备份文件mongodump --db logs --gzip输出 .bson.gz 文件,节省空间
mongorestoremongorestore --db=<newdb> <dump_dir>/<db>/<coll>.bson从 mongodump 备份恢复数据mongorestore --nsFrom="old.*" --nsTo="new.*" dump/默认插入(不覆盖);可用 --drop 先删除目标集合
--drop--drop恢复前删除目标集合mongorestore --drop dump/inventory/products.bson防止数据重复;慎用于生产环境
--nsFrom / --nsTo--nsFrom="prod.*" --nsTo="test.*"重命名数据库/集合(通配符)用于跨环境迁移(如 prod → test)支持 * 匹配;需 MongoDB 3.4+
增量备份结合 oplog(需副本集)实现时间点恢复(PITR)mongodump --oplog仅适用于副本集;单机模式不支持

8.3 CSV 与 JSON 格式处理

格式/操作说明处理要点注意事项
CSV 导入要求每行一条记录;字段由逗号分隔;可选标题行使用 --headerline--fields 指定字段名字段含逗号需用双引号包裹(如 "Smith, John"
CSV 导出限制仅支持扁平结构;嵌套字段需用点号展开--fields "name,address.city"数组字段导出为字符串(如 ["a","b"]"a,b"),无法还原
JSON 行格式(每行一个文档){ "name": "A" }
{ "name": "B" }
mongoimport 默认格式;高效且支持大文件不能是 JSON 数组(如 [ {...}, {...} ]),除非加 --jsonArray
JSON 数组格式[ { "name": "A" }, { "name": "B" } ]需使用 --jsonArray 选项内存占用高,不适用于超大文件
特殊类型处理Date、ObjectId、Binary 等在 JSON 中需特殊表示导出时自动转换为可读形式(如 ISODate("..."));导入时需保持格式一致手动编辑 JSON 时勿修改类型标识,否则导入失败
编码问题文件应为 UTF-8 编码非 UTF-8(如 GBK)可能导致乱码导入前用 iconv 转码:iconv -f gbk -t utf-8 input.csv > output.csv

8.4 备份策略与注意事项

策略/项说明推荐做法注意事项
全量备份频率完整备份整个数据库每日一次(结合增量);业务低峰期执行大数据库备份耗时长,需监控磁盘空间
增量备份仅备份自上次备份以来变更的数据副本集环境下使用 mongodump --oplog;或基于应用日志实现单机 MongoDB 无法原生支持增量备份
备份验证定期恢复测试以确保备份有效每月在隔离环境执行 restore + 查询验证”能备份” ≠ “能恢复”
存储位置备份文件应异地存储(不同服务器/云存储)使用 rsync、aws s3 cp 等同步到远程避免与数据库同机存放,防硬件故障
权限与安全备份文件可能含敏感数据加密存储(如 GPG);限制文件访问权限mongodump 不加密,需额外处理
自动化脚本通过 cron(Linux)或 Task Scheduler(Windows)定时执行示例:0 2 * * * /usr/bin/mongodump --gzip --out /backup/$(date +\%F)脚本需处理日志、错误通知、磁盘清理
锁与性能影响mongodump 默认不锁库,但大量读取可能影响性能在从节点(Secondary)执行备份主节点备份可能导致业务延迟
Point-in-Time Recovery恢复到任意时间点副本集 + oplog 备份;或结合文件系统快照需开启 --replSet 并保留足够 oplog 窗口

第九章:用户权限与安全配置

9.1 创建用户与角色管理

操作名称语法 / 命令用途说明代码示例注意事项
创建用户db.createUser({ user: "<name>", pwd: "<password>", roles: [ ... ] })在当前数据库创建新用户db.createUser({ user: "app_user", pwd: "secure123", roles: ["readWrite", "dbAdmin"] })必须在目标数据库中执行(如 use myApp
内置角色"read", "readWrite", "dbAdmin", "userAdmin", "clusterAdmin"预定义权限集合roles: ["readWrite", { role: "read", db: "analytics" }]角色作用域可跨库(通过 { role: "...", db: "..." }
自定义角色db.createRole({ role: "<name>", privileges: [...], roles: [...] })定义细粒度权限db.createRole({ role: "orderReader", privileges: [{ resource: { db: "sales", collection: "orders" }, actions: ["find"] }], roles: [] })userAdminuserAdminAnyDatabase 权限
修改用户密码db.changeUserPassword("<username>", "<newPassword>")更新用户密码db.changeUserPassword("app_user", "newPass456")需对用户所在数据库有 changeOwnPassword 或更高权限
删除用户db.dropUser("<username>")删除指定用户db.dropUser("temp_user")无法删除当前会话用户;需先切换或退出
查看用户信息db.getUser("<username>")db.getUsers()查询用户详情或列表db.getUsers({ showCredentials: false })默认不显示密码哈希;需 viewUser 权限

9.2 数据库访问控制(Authentication & Authorization)

安全机制说明配置方式注意事项
启用认证强制客户端提供有效凭据才能访问数据库启动 mongod 时加 --auth,或配置文件中设置 security.authorization: enabled未启用时所有连接均为 root 权限,极度危险
SCRAM-SHA-1/256默认认证机制(Salted Challenge Response Authentication Mechanism)创建用户时自动使用;无需额外配置SHA-256 更安全(MongoDB 4.0+),旧驱动可能仅支持 SHA-1
连接认证客户端连接时指定用户名、密码、认证源mongosh "mongodb://app_user:pwd@localhost:27017/myApp?authSource=myApp"authSource 指定用户所属数据库(通常为创建用户的库)
角色继承用户可拥有多个角色,权限合并roles: ["readWrite", "backup"]权限为”或”关系;无显式 deny 机制
最小权限原则用户仅授予必要权限应用用户不应拥有 dbAdminclusterAdmin避免使用 root 角色连接应用
认证失败行为连续失败多次可能触发延迟(防暴力破解)由服务器自动处理日志中记录 AuthenticationFailed 事件

9.3 网络绑定与防火墙设置

安全项说明配置方式注意事项
绑定 IP 地址限制 mongod 监听的网络接口配置文件:net.bindIp: 127.0.0.1,192.168.1.10
或启动参数 --bind_ip
默认 127.0.0.1(仅本地);生产环境应绑定内网 IP,禁止 0.0.0.0
端口默认 27017net.port: 27017可修改,但需同步更新客户端连接串
防火墙规则仅允许可信 IP 访问 MongoDB 端口Linux: ufw allow from 10.0.0.5 to any port 27017
AWS: 安全组入站规则
禁止公网直接暴露 MongoDB 端口
TLS/SSL 加密加密客户端与服务器通信配置 net.tls.mode: requireTLS + 证书路径需有效证书;自签名证书需客户端信任
连接池限制控制最大并发连接数net.maxIncomingConnections: 65536(默认)防止 DoS;根据系统资源调整
禁用 HTTP 接口旧版本(<3.2)支持 REST/HTTP 接口,存在风险确保未启用 --resthttpinterface新版本已移除该功能

9.4 审计与日志配置

功能说明配置方式注意事项
审计日志(Audit Log)记录敏感操作(如登录、删除、权限变更)企业版功能:auditLog: { destination: "file", format: "JSON", path: "/var/log/mongodb/audit.log" }社区版不支持;需 MongoDB Enterprise 或 Atlas
系统日志级别控制 mongod 输出日志详细程度systemLog.verbosity: 1(0~5,越高越详细)
或运行时 db.setLogLevel(1)
高 verbosity 影响性能;调试后应调低
慢查询日志自动记录执行时间超过阈值的操作operationProfiling.slowOpThresholdMs: 100
operationProfiling.mode: "slowOp"
日志写入 system.profile 集合(需提前开启)
日志轮转防止日志文件无限增长systemLog.logRotate: "reopen" + 外部工具(logrotate)logRotate: "rename" 为默认,需配合信号 SIGUSR1
敏感信息脱敏日志中避免记录密码、密钥MongoDB 自动过滤命令中的凭据字段但应用层日志仍需自行处理
日志存储位置建议独立磁盘分区systemLog.path: "/var/log/mongodb/mongod.log"避免与数据目录共用,防止 I/O 争抢

第十章:副本集与分片集群(高可用架构)

10.1 副本集原理与部署

概念/操作说明配置/命令示例注意事项
副本集(Replica Set)一组维护相同数据集的 mongod 实例,提供自动故障转移与数据冗余至少 3 节点(1 主 + 1 从 + 1 仲裁 或 3 数据节点)节点数应为奇数,避免脑裂;偶数时需配置仲裁节点
主节点(Primary)接受所有写操作,将 oplog 复制到从节点客户端仅向 Primary 写入任一时刻仅一个 Primary
从节点(Secondary)复制主节点 oplog 并异步应用,可配置为延迟复制或隐藏节点rs.add("host:port") 添加从节点默认不可读(需设置 readPreference)
仲裁节点(Arbiter)不存储数据,仅参与选举投票rs.addArb("arbiter-host:port")资源消耗低,但不提升读性能;不建议在主/从同机部署
初始化副本集在主节点执行 rs.initiate()js\nrs.initiate({\n _id: "rs0",\n members: [\n { _id: 0, host: "node1:27017" },\n { _id: 1, host: "node2:27017" }\n ]\n})\n所有节点必须能互相解析主机名并通信
查看状态rs.status()返回各节点健康状态、同步延迟、角色等关注 optimeDate 判断是否落后
选举机制当 Primary 失联(默认 10 秒),从节点发起选举自动进行,无需干预网络分区可能导致短暂无主;优先级(priority)影响胜出概率
Oplog主节点的操作日志(capped collection),从节点据此同步默认大小为 5% 磁盘(最大 50GB)若从节点落后超过 oplog 窗口,需全量同步(resync)

10.2 分片集群架构与组件(shard, config server, mongos)

组件作用说明部署要求注意事项
Shard(分片)存储实际数据的副本集(或独立 mongod,不推荐)每个 shard 是一个完整副本集(至少 3 节点)数据按 chunk 分布在多个 shard 上
Config Server存储集群元数据(如分片键范围、chunk 位置、数据库配置)MongoDB 3.4+ 必须为副本集(3 节点),不再支持单机元数据一致性关键;不可与 shard 共用节点
mongos查询路由器,接收客户端请求,路由到正确 shard,合并结果可部署多个(无状态),前端负载均衡应用直连 mongos,而非 shard;需配置所有 config server 地址
启动 mongosmongos --configdb <replSetName>/cfg1:27019,cfg2:27019,cfg3:27019 --port 27017必须指定 config server 副本集名称和成员不存储数据,崩溃后可重启
添加 Shard通过 mongos 执行 sh.addShard("rsName/host:port")js\nsh.addShard("shard1/node1:27017,node2:27017")\nshard 名称需全局唯一
启用数据库分片sh.enableSharding("<database>")必须先启用数据库,再对集合分片仅该库下集合可分片
对集合分片sh.shardCollection("<db>.<coll>", { <shardKey>: 1 })js\nsh.shardCollection("sales.orders", { orderId: 1 })\n分片键一旦设定不可更改(除非重建集合)

10.3 数据分布策略(哈希 vs 范围分片)

分片策略说明语法示例优缺点与注意事项
范围分片(Range)按分片键值连续范围划分 chunk(如 A–M, N–Z)sh.shardCollection("logs.events", { timestamp: 1 })✅ 适合范围查询(如时间窗口)
❌ 易导致热点(新数据集中写入最后一个 chunk)
哈希分片(Hash)对分片键计算哈希值,均匀分布 chunksh.shardCollection("users.profiles", { userId: "hashed" })✅ 写入负载均衡
❌ 范围查询需广播到所有 shard(性能差)
复合分片键多字段组合(如 { region: 1, userId: 1 }支持范围+哈希混合(首字段范围,后续字段可优化分布)需根据查询模式设计;首字段选择至关重要
Zone / Tag 感知分片将特定数据范围(如 region="CN")固定到指定 shardsh.addShardTag("shard1", "china")
sh.addTagRange("db.coll", { region: "CN" }, { region: "CN" }, "china")
用于数据本地化(GDPR)、冷热分离等场景
Chunk 大小默认 64MB可通过 db.adminCommand({ splitChunk: ..., size: 128 }) 调整(不推荐)过小 → 迁移频繁;过大 → 负载不均
Balancer后台进程,自动迁移 chunk 以均衡各 shard 数据量sh.setBalancerState(true) 启用可在业务低峰期运行;迁移期间可能影响性能

10.4 故障转移与读写分离

机制说明配置方式注意事项
自动故障转移副本集 Primary 宕机后,从节点自动选举新 Primary无需配置,依赖副本集心跳与选举协议切换通常在 10~30 秒内完成
读偏好(Read Preference)控制客户端从哪个节点读取数据连接字符串参数:?readPreference=secondary
或驱动中设置
选项:
- primary(默认)
- primaryPreferred
- secondary
- secondaryPreferred
- nearest
读扩展将只读查询路由到 Secondary,减轻 Primary 负载应用层显式设置 readPreference=secondary最终一致性:Secondary 可能有毫秒级延迟
写关注(Write Concern)控制写操作确认级别{ writeConcern: { w: "majority", j: true, wtimeout: 5000 } }w: "majority" 确保多数节点确认,防回滚;j: true 要求写入日志
分片集群高可用Config Server 副本集保障元数据可用
每个 Shard 为副本集保障数据可用
多 mongos 避免单点
部署时确保各组件均有冗余mongos 无状态,可弹性扩缩
手动干预选举临时阻止某节点成为 Primary(如维护)rs.freeze(0) 解除冻结
rs.stepDown(60) 主动降级 Primary
rs.reconfig() 可调整优先级
监控与告警关注指标:Replication lag、Unreachable nodes、Balancer status使用 MongoDB Cloud Manager、Ops Manager 或 Prometheus Exporter延迟 > oplog 窗口将导致从节点失效