首页 / MongoDB 入门教程 / 一对一关系建模

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 小结

一对一关系用内嵌文档最直观,读快、写原子。记住点号访问内嵌字段,更新和建索引都靠它。