跳到主要内容

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:开源监控工具