MongoDB提供两种主要的数据建模方式:
// 将相关数据嵌入到同一个文档中
{
_id: ObjectId("..."),
name: "张三",
email: "zhangsan@example.com",
address: {
street: "长安街1号",
city: "北京",
zipCode: "100000"
},
orders: [
{
orderId: "order001",
product: "笔记本电脑",
price: 5999,
date: ISODate("2026-01-15")
},
{
orderId: "order002",
product: "鼠标",
price: 99,
date: ISODate("2026-01-20")
}
]
}
// 用户集合
{
_id: "user123",
name: "张三",
email: "zhangsan@example.com"
}
// 订单集合
{
_id: "order001",
userId: "user123", // 引用用户ID
product: "笔记本电脑",
price: 5999,
date: ISODate("2026-01-15")
}
// 查询时需要关联
db.orders.aggregate([
{
$lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "user"
}
}
])
| 场景 | 推荐方式 | 原因 |
|---|---|---|
| 一对一关系 | 嵌入式 | 数据紧密相关,一起查询 |
| 一对少(1-100) | 嵌入式 | 数组不会太大 |
| 一对多(100+) | 引用 | 避免文档过大 |
| 多对多 | 引用 | 避免数据冗余 |
| 读多写少 | 嵌入式 | 优化读性能 |
| 写多读少 | 引用 | 减少更新复杂度 |
// 传统方式(字段过多)
{
_id: 1,
name: "商品A",
color_red: true,
color_blue: false,
size_S: true,
size_M: false,
size_L: true
// ... 更多属性
}
// 属性模式(灵活扩展)
{
_id: 1,
name: "商品A",
attributes: [
{ key: "color", value: "red" },
{ key: "color", value: "blue" },
{ key: "size", value: "S" },
{ key: "size", value: "L" }
]
}
// 查询
db.products.find({
"attributes": {
$elemMatch: { key: "color", value: "red" }
}
})
// 创建索引
db.products.createIndex({ "attributes.key": 1, "attributes.value": 1 })
// 物联网传感器数据(每秒一条)
// 传统方式:每条数据一个文档(数据量巨大)
{
sensorId: "sensor001",
temperature: 25.5,
timestamp: ISODate("2026-02-03T10:00:00Z")
}
// 桶模式:按小时聚合数据
{
sensorId: "sensor001",
date: ISODate("2026-02-03T10:00:00Z"),
measurements: [
{ time: 0, temp: 25.5 },
{ time: 1, temp: 25.6 },
{ time: 2, temp: 25.4 },
// ... 3600条数据
],
count: 3600,
avgTemp: 25.5,
minTemp: 24.8,
maxTemp: 26.2
}
// 电影评论(可能有数万条)
// 在电影文档中只嵌入最新的10条评论
{
_id: "movie123",
title: "电影名称",
recentReviews: [
{ user: "user1", rating: 5, comment: "很好看" },
{ user: "user2", rating: 4, comment: "不错" }
// ... 最多10条
],
totalReviews: 15000
}
// 所有评论存储在单独的集合中
// reviews集合
{
movieId: "movie123",
user: "user1",
rating: 5,
comment: "很好看",
date: ISODate("2026-02-03")
}
// 订单中嵌入常用的用户信息
{
_id: "order001",
userId: "user123",
// 嵌入常用字段,避免每次都关联查询
userName: "张三",
userEmail: "zhangsan@example.com",
items: [...],
total: 5999
}
// 完整的用户信息仍在users集合中
// 如需更多信息,再查询users集合
// 保存文档的历史版本
{
_id: "doc123",
title: "文档标题",
content: "当前内容",
version: 3,
history: [
{
version: 1,
content: "初始内容",
updatedAt: ISODate("2026-01-01"),
updatedBy: "user1"
},
{
version: 2,
content: "修改后的内容",
updatedAt: ISODate("2026-01-15"),
updatedBy: "user2"
}
]
}
// 适度的数据冗余可以提升性能
// 订单中冗余商品信息
{
_id: "order001",
userId: "user123",
items: [
{
productId: "prod123",
// 冗余商品信息(下单时的快照)
productName: "笔记本电脑",
productPrice: 5999,
productImage: "laptop.jpg",
quantity: 1
}
],
total: 5999,
createdAt: ISODate("2026-02-03")
}
// 好处:
// 1. 查询订单时不需要关联商品表
// 2. 保存下单时的商品信息(价格可能会变)
// 3. 即使商品被删除,订单信息仍完整
// 文章集合(嵌入评论和标签)
{
_id: ObjectId("..."),
title: "MongoDB数据建模最佳实践",
author: {
id: "user123",
name: "张三",
avatar: "avatar.jpg"
},
content: "文章内容...",
tags: ["MongoDB", "数据库", "NoSQL"],
comments: [
{
id: "comment1",
user: "李四",
content: "写得很好",
createdAt: ISODate("2026-02-01")
}
// 只嵌入最新的20条评论
],
stats: {
views: 1500,
likes: 89,
commentCount: 156
},
createdAt: ISODate("2026-01-15"),
updatedAt: ISODate("2026-02-03")
}
// 所有评论存储在单独的集合
// comments集合
{
_id: "comment1",
postId: ObjectId("..."),
userId: "user456",
userName: "李四",
content: "写得很好",
createdAt: ISODate("2026-02-01")
}
// 创建集合时定义Schema
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "age"],
properties: {
name: {
bsonType: "string",
description: "必须是字符串"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "必须是有效的邮箱"
},
age: {
bsonType: "int",
minimum: 0,
maximum: 150,
description: "年龄必须在0-150之间"
}
}
}
}
})