MongoDB 数据库
欢迎来到 MongoDB 数据库知识库!
🍃 MongoDB 简介
MongoDB 是最流行的 NoSQL 文档数据库,以 JSON 格式存储数据。它提供了灵活的模式、强大的查询能力和横向扩展性,特别适合处理非结构化和半结构化数据。
🎯 MongoDB vs 关系型数据库
| 概念 | MongoDB | MySQL/PostgreSQL |
|---|---|---|
| 数据单位 | Document (文档) | Row (行) |
| 集合 | Collection | Table (表) |
| 数据库 | Database | Database |
| Schema | 灵活,动态 | 固定,需预定义 |
| 关系 | 嵌入或引用 | 外键关联 |
| 扩展 | 横向扩展(分片) | 纵向扩展为主 |
🎯 适用场景
✅ 特别适合
- 快速迭代 - Schema 灵活,无需迁移
- 半结构化数据 - JSON 格式数据
- 大数据量 - 分片集群支持
- 实时分析 - 聚合管道
- 内容管理 - CMS、博客
- 物联网 - 日志、传感器数据
- 移动应用 - 用户配置、社交数据
⚠️ 不太适合
- 复杂事务(虽然支持多文档事务)
- 复杂的多表关联
- 需要强一致性的场景
🎯 学习路线
第一阶段:MongoDB 基础 (1-2周)
基本概念
- 文档、集合、数据库
- BSON 格式
- ObjectId
CRUD 操作
- 插入文档
- 查询文档
- 更新文档
- 删除文档
第二阶段:高级查询 (2-3周)
查询操作符
- 比较操作符
- 逻辑操作符
- 数组操作符
聚合管道
- $match、$project
- $group、$sort
- $lookup 关联
第三阶段:索引与优化 (1-2周)
索引
- 单字段索引
- 复合索引
- 文本索引
- 地理空间索引
性能优化
- explain() 分析
- 索引优化
- 查询优化
第四阶段:高可用与分片 (持续)
副本集
- 主从复制
- 自动故障转移
分片集群
- 水平扩展
- 分片键选择
✨ MongoDB 特点
✅ 核心优势
- 灵活的文档模型 - JSON 格式,动态 Schema
- 强大的查询 - 丰富的查询操作符
- 聚合框架 - 数据处理和分析
- 水平扩展 - 自动分片
- 高可用 - 副本集自动故障转移
- 索引支持 - 多种索引类型
- 原子操作 - 文档级别的原子性
🔧 数据类型
- String(字符串)
- Number(数字)
- Boolean(布尔)
- Date(日期)
- Array(数组)
- Object(嵌入文档)
- ObjectId(文档ID)
- Binary Data(二进制)
- Null
📖 CRUD 操作
插入文档
javascript
// 插入单个文档
db.users.insertOne({
username: "张三",
email: "zhang@example.com",
age: 25,
tags: ["JavaScript", "MongoDB"],
address: {
city: "北京",
district: "朝阳区"
},
createdAt: new Date()
});
// 插入多个文档
db.users.insertMany([
{ username: "李四", age: 30 },
{ username: "王五", age: 28 }
]);查询文档
javascript
// 查询所有
db.users.find();
// 条件查询
db.users.find({ age: { $gt: 25 } });
// 查询单个
db.users.findOne({ username: "张三" });
// 指定返回字段
db.users.find({}, { username: 1, email: 1, _id: 0 });
// 排序和限制
db.users.find().sort({ age: -1 }).limit(10);
// 数组查询
db.users.find({ tags: "JavaScript" });
db.users.find({ tags: { $all: ["JavaScript", "MongoDB"] } });
// 嵌入文档查询
db.users.find({ "address.city": "北京" });更新文档
javascript
// 更新单个文档
db.users.updateOne(
{ username: "张三" },
{ $set: { age: 26 } }
);
// 更新多个文档
db.users.updateMany(
{ age: { $lt: 18 } },
{ $set: { status: "minor" } }
);
// 替换文档
db.users.replaceOne(
{ username: "张三" },
{ username: "张三", age: 26, email: "new@example.com" }
);
// 数组操作
db.users.updateOne(
{ username: "张三" },
{ $push: { tags: "Node.js" } }
);
db.users.updateOne(
{ username: "张三" },
{ $pull: { tags: "JavaScript" } }
);删除文档
javascript
// 删除单个文档
db.users.deleteOne({ username: "张三" });
// 删除多个文档
db.users.deleteMany({ age: { $lt: 18 } });
// 删除所有文档
db.users.deleteMany({});🔍 查询操作符
比较操作符
javascript
// $eq, $ne, $gt, $gte, $lt, $lte
db.users.find({ age: { $gte: 18, $lte: 30 } });
// $in, $nin
db.users.find({ status: { $in: ["active", "pending"] } });逻辑操作符
javascript
// $and
db.users.find({
$and: [
{ age: { $gte: 18 } },
{ status: "active" }
]
});
// $or
db.users.find({
$or: [
{ age: { $lt: 18 } },
{ age: { $gt: 60 } }
]
});
// $not
db.users.find({ age: { $not: { $gte: 18 } } });元素操作符
javascript
// $exists - 字段是否存在
db.users.find({ email: { $exists: true } });
// $type - 字段类型
db.users.find({ age: { $type: "number" } });📊 聚合管道
javascript
// 统计每个城市的用户数量
db.users.aggregate([
{
$group: {
_id: "$address.city",
count: { $sum: 1 },
avgAge: { $avg: "$age" }
}
},
{
$sort: { count: -1 }
}
]);
// 多阶段聚合
db.orders.aggregate([
// 过滤
{ $match: { status: "completed" } },
// 关联用户表
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
},
// 展开数组
{ $unwind: "$user" },
// 投影
{
$project: {
orderNo: 1,
amount: 1,
"user.username": 1
}
},
// 排序
{ $sort: { amount: -1 } },
// 限制
{ $limit: 10 }
]);🔍 索引
创建索引
javascript
// 单字段索引
db.users.createIndex({ username: 1 }); // 1: 升序, -1: 降序
// 复合索引
db.users.createIndex({ age: 1, username: 1 });
// 唯一索引
db.users.createIndex({ email: 1 }, { unique: true });
// 文本索引(全文搜索)
db.articles.createIndex({ content: "text" });
// 部分索引
db.users.createIndex(
{ email: 1 },
{ partialFilterExpression: { age: { $gte: 18 } } }
);
// TTL 索引(自动过期)
db.sessions.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600 }
);
// 查看索引
db.users.getIndexes();
// 删除索引
db.users.dropIndex("username_1");索引优化
javascript
// 查询计划分析
db.users.find({ age: { $gt: 25 } }).explain("executionStats");
// 关注指标:
// - executionTimeMillis: 执行时间
// - totalDocsExamined: 扫描文档数
// - totalKeysExamined: 扫描索引数
// - stage: IXSCAN(索引扫描)vs COLLSCAN(全集合扫描)🚀 副本集
Primary
(主节点)
/ \
写入 / \ 同步
/ \
Secondary Secondary
(从节点) (从节点)
\ /
读取 \ / 读取特点
- 自动故障转移 - 主节点故障时自动选举
- 读写分离 - 主节点写,从节点读
- 数据冗余 - 多个副本保证数据安全
🔀 分片集群
Client
|
mongos (路由)
|
---------------
| | |
Shard1 Shard2 Shard3特点
- 水平扩展 - 数据分布在多个分片
- 自动均衡 - 数据自动迁移
- 分片键 - 决定数据如何分片
💡 最佳实践
文档设计
- 根据查询模式设计
- 合理使用嵌入 vs 引用
- 避免过大的文档(<16MB)
- 使用有意义的字段名
索引策略
- 为高频查询创建索引
- 复合索引字段顺序很重要
- 定期检查索引使用情况
- 删除未使用的索引
查询优化
- 使用投影减少数据传输
- 使用 explain() 分析查询
- 避免全集合扫描
- 合理使用聚合管道
数据建模
- 一对一:嵌入
- 一对多(少):嵌入
- 一对多(多):引用
- 多对多:引用 + 中间集合
📖 学习资源
官方资源
推荐书籍
- 《MongoDB 权威指南》
- 《MongoDB 实战》
- 《深入学习 MongoDB》
工具推荐
- MongoDB Compass - 官方 GUI 工具
- Studio 3T - 功能强大的客户端
- mongostat - 性能监控
- mongotop - 实时统计
准备好了吗?开始你的 MongoDB 学习之旅!