作为一名资深数据库架构师,我将带领您深入探索 MongoDB,一个以高性能、高可用性和易伸缩性著称的文档型数据库。与传统的关系型数据库不同,MongoDB 采用 JSON 类似的 BSON (Binary JSON) 格式存储数据,提供了极大的灵活性,非常适合处理非结构化和半结构化数据,以及需要快速迭代和横向扩展的应用场景。
理解 MongoDB 的基石是掌握其核心概念,它们与关系型数据库有着相似但不同的对应关系。
| 关系型数据库 (SQL) | MongoDB (NoSQL) | 说明 |
|---|---|---|
| 数据库 (Database) | 数据库 (Database) | 物理文件系统的容器,包含多个集合。 |
| 表 (Table) | 集合 (Collection) | 一组文档的集合,类似于表,但无需预定义结构。 |
| 行 (Row) | 文档 (Document) | MongoDB 的核心数据单元,存储为 BSON 格式,由键值对组成。 |
| 列 (Column) | 字段 (Field) | 文档中的键值对,值的类型可以是字符串、数字、数组、嵌套文档等。 |
| 主键 (Primary Key) | 主键 (_id Field) |
每个文档都有一个唯一的 _id 字段,作为其主键。 |
| 表连接 (JOIN) | 嵌入文档/引用 (Embedded Documents/References) | MongoDB 通常通过嵌入文档来处理一对一、一对多的关系,或通过引用(ID)来处理多对多关系。 |
文档是 MongoDB 中最基本的数据单位,由键值对组成。键是字符串,值可以是各种 BSON 数据类型,包括数组和嵌套文档。这使得文档可以非常灵活地表示复杂的数据结构。
{
"_id": ObjectId("60c72b2f9e4f5a3b7c8d9e01"),
"name": "Alice Smith",
"age": 30,
"email": "[email protected]",
"address": {
"street": "123 Main St",
"city": "New York",
"zip": "10001"
},
"interests": ["reading", "hiking", "cooking"],
"createdAt": ISODate("2023-10-26T10:00:00Z")
}
集合是文档的组。它类似于关系型数据库中的表,但与表不同的是,集合不强制要求文档具有相同的结构(模式自由 Schema-less)。
数据库是集合的容器。一个 MongoDB 实例可以承载多个数据库。
本节简要说明安装和启动 MongoDB 的步骤。以 Linux 为例,其他操作系统类似,请参考官方文档。
# For Ubuntu
sudo apt update
sudo apt install mongodb-org
# For macOS (using Homebrew)
brew tap mongodb/brew
brew install [email protected]
# For Linux (systemd)
sudo systemctl start mongod
sudo systemctl enable mongod # Set to start on boot
# For macOS (Homebrew services)
brew services start [email protected]
mongosh
成功连接后,您将进入 MongoDB Shell,可以开始执行数据库操作。
CRUD (Create, Read, Update, Delete) 是数据库操作的四大基本功能。
// 切换到或创建数据库
use myDatabase
// 插入单个文档
db.users.insertOne({ name: "Bob", age: 25, status: "active" })
// 插入多个文档
db.products.insertMany([
{ name: "Laptop", price: 1200, category: "Electronics" },
{ name: "Keyboard", price: 75, category: "Electronics" },
{ name: "Mouse", price: 30, category: "Accessories" }
])
// 查询所有文档
db.users.find({})
// 查询满足条件的文档
db.users.find({ age: { $gt: 20, $lt: 30 } }) // 年龄大于20小于30
db.products.find({ category: "Electronics" }).pretty() // 格式化输出
// 查询指定字段
db.users.find({}, { name: 1, age: 1, _id: 0 }) // 只显示name和age字段,不显示_id
// 复杂查询:逻辑操作符、数组查询等
db.users.find({
$or: [{ age: { $gt: 25 } }, { status: "inactive" }],
"address.city": "New York"
})
// 更新单个文档
db.users.updateOne(
{ name: "Bob" },
{ $set: { age: 26, status: "inactive" } }
)
// 更新多个文档
db.products.updateMany(
{ category: "Electronics" },
{ $inc: { price: 5 } } // 所有电子产品价格增加5
)
// 数组操作: $push, $pull, $addToSet 等
db.users.updateOne(
{ name: "Alice Smith" },
{ $push: { interests: "photography" } } // 添加一个兴趣
)
// 删除单个文档
db.users.deleteOne({ name: "Bob" })
// 删除多个文档
db.products.deleteMany({ category: "Accessories" })
// 删除集合中的所有文档
db.myCollection.deleteMany({})
// 删除整个集合
db.myCollection.drop()
索引是提高查询性能的关键。MongoDB 支持多种类型的索引,包括单字段索引、复合索引、多键索引、文本索引和地理空间索引。
// 创建单字段升序索引
db.users.createIndex({ age: 1 })
// 创建复合索引
db.products.createIndex({ category: 1, price: -1 }) // 先按品类升序,再按价格降序
// 后台创建索引 (不阻塞写入操作)
db.logs.createIndex({ timestamp: 1 }, { background: true })
// 查看集合的索引
db.users.getIndexes()
聚合框架是 MongoDB 中处理数据转换和分析的强大工具。它通过管道 (pipeline) 的方式,将文档经过一系列的阶段处理,最终输出所需的结果。
db.orders.aggregate([
// 阶段1: 匹配 - 筛选出状态为"completed"的订单
{ $match: { status: "completed" } },
// 阶段2: 分组 - 按客户ID分组,计算总金额和订单数量
{ $group: {
_id: "$customerId",
totalAmount: { $sum: "$amount" },
orderCount: { $sum: 1 }
}},
// 阶段3: 排序 - 按总金额降序排列
{ $sort: { totalAmount: -1 } },
// 阶段4: 限制 - 只取前5个结果
{ $limit: 5 }
])
常用聚合阶段:$match, $group, $project, $sort, $limit, $skip, $unwind 等。
复制集是 MongoDB 提供高可用性的核心机制。它由一个主节点 (Primary) 和一个或多个从节点 (Secondary) 组成。主节点负责所有写入操作,并将数据同步到从节点。当主节点故障时,复制集会自动选举一个新的主节点,确保服务的持续可用性。
Primary (读写) ---> Secondary (只读/数据同步)
| /
| /
V V
Secondary (只读/数据同步)
分片是 MongoDB 实现横向扩展 (水平伸缩) 的方法。当数据量非常大或读写负载很高时,可以将数据分散存储在多个服务器(分片 Shards)上。每个分片独立存储一部分数据,客户端通过路由进程 (mongos) 访问数据。
分片架构的主要组件:
从 MongoDB 4.0 开始,MongoDB 支持多文档 ACID 事务,跨单个或多个集合、数据库和分片。这使得 MongoDB 在需要强一致性的复杂业务场景中更具吸引力。
const session = client.startSession();
session.startTransaction();
try {
const coll1 = session.client.db('mydb1').collection('coll1');
const coll2 = session.client.db('mydb2').collection('coll2');
await coll1.insertOne({ item: 1, quantity: 10 }, { session });
await coll2.updateOne({ item: 2 }, { $inc: { quantity: -10 } }, { session });
await session.commitTransaction();
console.log('Transaction committed.');
} catch (error) {
await session.abortTransaction();
console.error('Transaction aborted:', error);
} finally {
session.endSession();
}
$inc, $set) 和文档嵌入模式,只在真正需要跨多个文档或集合保证原子性时使用事务。
$match 阶段字段创建索引。使用 explain() 来分析查询性能。insertMany(), updateMany(), bulkWrite() 来减少网络开销。MongoDB 凭借其灵活的数据模型、强大的查询能力和高可伸缩性,已成为现代应用开发中不可或缺的数据库解决方案。通过深入理解其核心概念,掌握数据操作技巧,并善用高级特性如索引、聚合、复制集和分片,您将能够构建出高效、可用且易于扩展的应用程序。持续的性能监控和遵循最佳实践是确保 MongoDB 数据库健康运行的关键。希望这份教程能帮助您更好地掌握 MongoDB!