MongoDB 入门教程
一对一关系建模
本教程共 50 篇 · 第 37 篇 · 更新于 2026-07-30 · 约 3 分钟阅读
MongoDBMongoDB 入门教程一对一数据建模内嵌文档反范式化
37. 一对一关系建模
本节目标:掌握一对一关系的内嵌建模法,能写出一个带内嵌子文档的用户集合。
一对一(One-to-One)指一个实体只对应另一个实体。比如一个用户对应一份个人资料,一份资料也从属于一个用户。这类关系在 MongoDB 里几乎总是用内嵌最省事。
37.1 场景:用户和他的资料
我们的 users 集合长这样:_id, name, email, age, city, tags, registered_at。现在要给每个用户加一份资料,含手机号和简介。
最自然的方式,是把资料作为内嵌文档(Embedded Document)直接放进用户里:
// 内嵌资料的一对一建模
test> db.users.insertOne({
_id: 1,
name: "小明",
email: "ming@example.com",
age: 28,
city: "杭州",
tags: ["vip", "early"],
registered_at: new Date("2025-01-15"),
profile: {
phone: "13800000000",
bio: "爱折腾的后端工程师",
verified: true
}
})
这样一个文档就把用户和资料都装下了。取用户时资料自动跟着来,不用多查一次。
37.2 查询内嵌文档
查「已认证且住在杭州的用户」,直接点内嵌字段即可:
test> db.users.find(
{ city: "杭州", "profile.verified": true },
{ name: 1, "profile.phone": 1 }
)
注意内嵌字段要用点号(dot notation)访问,比如 profile.phone。这是 MongoDB 访问嵌套字段的标准写法。
Tip内嵌字段建索引也用它:
db.users.createIndex({ "profile.phone": 1 }),和我们后面索引章讲的一致。
37.3 更新内嵌字段
改资料里的手机号,用 $set 配点号路径:
test> db.users.updateOne(
{ _id: 1 },
{ $set: { "profile.phone": "13900000000" } }
)
更新发生在同一个文档内,是原子的(Atomic)。要么改成功,要么没改,不会出现「用户改了、资料没改」的中间态。
37.4 什么时候不用内嵌
一对一也不是必须内嵌。出现下面情况,可以改用引用:
- 资料体积很大,且多数查询根本用不到它。
- 资料被别的系统单独管理,需要独立读写。
// 改用引用:资料独立成集合,用户只存 profile_id
test> db.profiles.insertOne({ _id: 100, user_id: 1, phone: "13800000000", bio: "..." })
test> db.users.updateOne({ _id: 1 }, { $set: { profile_id: 100 } })
Note一对一默认内嵌。只有「大对象、少访问、需独立」才拆出去。别为了对称而拆。
37.5 小结
一对一关系用内嵌文档最直观,读快、写原子。记住点号访问内嵌字段,更新和建索引都靠它。