MongoDB
介绍
MongoDB是一个基于分布式文件存储的开源NoSQL数据库系统,由C++语言编写。它是一个面向文档的数据库,使用JSON-like的BSON格式存储数据,具有高性能、高可用性和易扩展性的特点。MongoDB适用于处理大量非结构化或半结构化数据,特别适合敏捷开发和迭代式开发流程。
原理
面向文档的存储
MongoDB使用BSON(Binary JSON)格式存储数据,每个文档是一个类似JSON的对象,包含键值对。文档可以嵌套,字段可以是数组、对象等复杂类型,不需要固定的模式结构。
集合和数据库
- 集合(Collection):一组文档的集合,类似于关系数据库中的表
- 数据库(Database):一组集合的集合,每个数据库有独立的权限控制
- 命名空间:集合的完整名称,格式为
数据库名.集合名
索引机制
MongoDB支持多种索引类型:
- 单字段索引:最基本的索引类型,基于单个字段创建
- 复合索引:基于多个字段创建的索引
- 多键索引:用于数组字段的索引
- 地理空间索引:用于地理位置数据的索引
- 文本索引:用于文本搜索的索引
- 哈希索引:用于基于哈希的分片
分片和复制
- 分片(Sharding):将数据分布在多个服务器上,提高存储容量和性能
- 复制(Replication):创建数据的多个副本,提高数据可用性和可靠性
- 副本集(Replica Set):一组维护相同数据集的MongoDB服务器
- 主节点(Primary):处理所有写操作和读请求
- 从节点(Secondary):复制主节点的数据,处理读请求
事务支持
MongoDB 4.0及以上版本支持多文档事务,满足ACID特性:
- 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败
- 一致性(Consistency):事务执行前后,数据库状态保持一致
- 隔离性(Isolation):多个事务并发执行时,彼此不影响
- 持久性(Durability):事务提交后,数据修改永久保存
图示
MongoDB架构
┌─────────────────────────────────────────────────────────────────┐
│ 应用程序 │
└───────────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────────▼─────────────────────────────────┐
│ MongoDB驱动 │
└───────────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────────▼─────────────────────────────────┐
│ MongoDB实例 │
├───────────────────────────────┬─────────────────────────────────┤
│ 数据库1 │ 数据库2 │
├───────────┬───────────────────┼──────────────┬──────────────────┤
│ 集合1 │ 集合2 │ 集合3 │ 集合4 │
└───────────┴───────────────────┴──────────────┴──────────────────┘
副本集架构
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 主节点 │◄─────►│ 从节点 │◄─────►│ 从节点 │
│ (Primary) │ │ (Secondary) │ │ (Secondary) │
└──────┬────────┘ └───────────────┘ └───────────────┘
│
│ 选举
▼
┌───────────────┐
│ 仲裁节点 │
│ (Arbiter) │
└───────────────┘
分片集群架构
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 路由服务器 │◄─────►│ 配置服务器 │◄─────►│ 分片1 │
│ (mongos) │ │ (configsvr) │ │ (shard1) │
└──────┬────────┘ └───────────────┘ └───────────────┘
│ ▲
│ │
▼ │
┌───────────────┐ ┌───────────────┐ ┌────┴──────────┐
│ 分片2 │◄─────►│ 分片3 │◄─────►│ 分片4 │
│ (shard2) │ │ (shard3) │ │ (shard4) │
└───────────────┘ └───────────────┘ └───────────────┘
实例
连接数据库
const { MongoClient } = require('mongodb');
// 连接URL
const url = 'mongodb://localhost:27017';
// 数据库名称
const dbName = 'mydatabase';
// 创建客户端
const client = new MongoClient(url);
// 连接数据库
async function connect() {
try {
await client.connect();
console.log('成功连接到数据库');
const db = client.db(dbName);
return db;
} catch (err) {
console.error('连接数据库失败:', err);
throw err;
}
}
插入文档
async function insertDocument() {
try {
const db = await connect();
const collection = db.collection('users');
// 插入单个文档
const result = await collection.insertOne({
name: '张三',
age: 30,
email: 'zhangsan@example.com',
address: {
city: '北京',
street: '朝阳区'
},
hobbies: ['读书', '旅行', '运动'],
createdAt: new Date()
});
console.log('插入成功,文档ID:', result.insertedId);
} catch (err) {
console.error('插入文档失败:', err);
} finally {
client.close();
}
}
insertDocument();
查询文档
async function findDocuments() {
try {
const db = await connect();
const collection = db.collection('users');
// 查询所有文档
const allUsers = await collection.find({}).toArray();
console.log('所有用户:', allUsers);
// 条件查询
const ageGreaterThan25 = await collection.find({ age: { $gt: 25 } }).toArray();
console.log('年龄大于25的用户:', ageGreaterThan25);
// 投影查询(只返回指定字段)
const nameAndEmail = await collection.find({}).project({ name: 1, email: 1, _id: 0 }).toArray();
console.log('用户姓名和邮箱:', nameAndEmail);
// 排序和限制
const sortedUsers = await collection.find({}).sort({ age: -1 }).limit(5).toArray();
console.log('按年龄降序排列的前5个用户:', sortedUsers);
} catch (err) {
console.error('查询文档失败:', err);
} finally {
client.close();
}
}
findDocuments();
更新文档
async function updateDocument() {
try {
const db = await connect();
const collection = db.collection('users');
// 更新单个文档
const result = await collection.updateOne(
{ name: '张三' }, // 查询条件
{ $set: { age: 31, 'address.city': '上海' } } // 更新操作
);
console.log('更新成功,匹配的文档数:', result.matchedCount);
console.log('更新的文档数:', result.modifiedCount);
// 更新多个文档
const resultMultiple = await collection.updateMany(
{ age: { $lt: 25 } }, // 查询条件
{ $inc: { age: 1 } } // 更新操作(年龄加1)
);
console.log('批量更新成功,匹配的文档数:', resultMultiple.matchedCount);
console.log('批量更新的文档数:', resultMultiple.modifiedCount);
} catch (err) {
console.error('更新文档失败:', err);
} finally {
client.close();
}
}
updateDocument();
删除文档
async function deleteDocument() {
try {
const db = await connect();
const collection = db.collection('users');
// 删除单个文档
const result = await collection.deleteOne({ name: '张三' });
console.log('删除成功,删除的文档数:', result.deletedCount);
// 删除多个文档
const resultMultiple = await collection.deleteMany({ age: { $gt: 40 } });
console.log('批量删除成功,删除的文档数:', resultMultiple.deletedCount);
} catch (err) {
console.error('删除文档失败:', err);
} finally {
client.close();
}
}
deleteDocument();
聚合查询
async function aggregateDocuments() {
try {
const db = await connect();
const collection = db.collection('users');
// 聚合查询示例:按城市分组,计算每个城市的用户数量
const result = await collection.aggregate([
{ $group: { _id: '$address.city', count: { $sum: 1 } } },
{ $sort: { count: -1 } }
]).toArray();
console.log('按城市分组的用户数量:', result);
} catch (err) {
console.error('聚合查询失败:', err);
} finally {
client.close();
}
}
aggregateDocuments();
专业解决方案
数据模型设计
- 嵌入式文档:将相关数据嵌入到一个文档中,适合一对一或一对多关系
- 引用式文档:通过引用ID关联不同文档,适合多对多关系
- 反规范化:为提高查询性能,适当冗余数据
- 数据一致性:在嵌入式和引用式之间找到平衡
- 模式验证:使用MongoDB的模式验证功能确保数据质量
索引优化
- 选择合适的字段:在常用查询字段上创建索引
- 复合索引顺序:将选择性高的字段放在前面
- 避免过度索引:过多的索引会影响写入性能
- 覆盖索引:包含查询所需的所有字段,避免额外的文档读取
- 索引碎片整理:定期重建索引以提高性能
查询优化
- 投影查询:只返回需要的字段,减少数据传输
- 分页查询:使用limit()和skip()进行分页,大集合使用range查询
- 避免全表扫描:确保查询条件使用索引
- 聚合框架:使用聚合管道进行复杂数据处理
- 查询分析器:使用explain()分析查询性能
高可用性
- 副本集:配置至少3个节点的副本集,确保数据冗余
- 自动故障转移:当主节点故障时,自动选举新的主节点
- 读写分离:将读请求分发到从节点,提高吞吐量
- 延迟节点:配置延迟同步的节点,用于恢复误删除的数据
扩展性
- 水平扩展:使用分片集群扩展存储容量和性能
- 分片键选择:选择分布均匀、查询频繁的字段作为分片键
- 预分片:在数据量增长前预先创建分片
- 范围分片:基于分片键的范围将数据分布到不同分片
- 哈希分片:基于分片键的哈希值将数据分布到不同分片
安全
- 认证:启用用户名和密码认证
- 授权:为不同用户分配适当的角色和权限
- 加密:启用传输加密(TLS/SSL)和静态数据加密
- 审计日志:记录数据库操作,便于安全审计
- IP白名单:限制只允许特定IP地址访问数据库
备份和恢复
- 定期备份:使用mongodump工具定期备份数据
- 增量备份:使用oplog进行增量备份
- 点时间恢复:结合全量备份和oplog实现任意时间点的恢复
- 自动备份:配置定时任务自动执行备份
监控和性能调优
- MongoDB Atlas:云服务提供的监控工具
- MongoDB Compass:官方GUI工具,提供性能分析功能
- Prometheus和Grafana:开源监控解决方案
- 慢查询日志:记录执行时间超过阈值的查询
- 性能指标:监控吞吐量、延迟、连接数等关键指标
工具推荐
- MongoDB Compass:官方GUI管理工具
- Robo 3T:开源MongoDB管理工具
- Studio 3T:功能强大的MongoDB IDE
- MongoDB Atlas:云数据库服务
- mongodump/mongorestore:备份和恢复工具
- mongoexport/mongoimport:数据导入导出工具
- Percona Monitoring and Management:开源监控工具