在MongoDB中以一对一的关系存储文档引用的正确方法

时间:2014-12-02 10:43:20

标签: mongodb entity-relationship relationships

我有两个MongoDB集合usercustomer,它们是一对一的关系。我是MongoDB的新手,虽然我安装了Mongoose,但我正在尝试手动插入文档。我不确定在MongoDB中存储文档引用的正确方法是什么。

我正在使用规范化数据模型,这是我customer的Mongoose模式快照:

/** Parent user object */
user: {
    type: Schema.Types.ObjectId,
    ref: "User",
    required: true
}

用户

{ 
    "_id" : ObjectId("547d5c1b1e42bd0423a75781"), 
    "name" : "john", 
    "email" : "test@localhost.com", 
    "phone" : "01022223333", 
}

我想在user文档中引用此customer文档。以下哪项是正确的 - (A)或(B)?

客户(A)

{ 
    "_id" : ObjectId("547d916a660729dd531f145d"), 
    "birthday" : "1983-06-28", 
    "zipcode" : "12345", 
    "address" : "1, Main Street", 
    "user" : ObjectId("547d5c1b1e42bd0423a75781")
}

客户(B)

{ 
    "_id" : ObjectId("547d916a660729dd531f145d"), 
    "birthday" : "1983-06-28", 
    "zipcode" : "12345", 
    "address" : "1, Main Street", 
    "user" : {
        "_id" : ObjectId("547d5c1b1e42bd0423a75781")
    }
}

4 个答案:

答案 0 :(得分:3)

记住这些事情

嵌入更适合......

  • 小子文档
  • 不经常更改的数据
  • 当最终的一致性可以接受时
  • 少量增长的文件
  • 您经常需要执行第二次查询以获取快速读取的数据

参考更适合......

  • 大型子文档
  • 易变数据
  • 当需要立即一致时
  • 增长量大的文件
  • 您经常从结果中排除的数据
  • 快速写入

变体A更好。 您也可以将populate与Mongoose一起使用

答案 1 :(得分:2)

使用变体A.只要您不想对任何其他数据(例如用户的名称)进行非规范化,就不需要创建子对象。

这也避免了索引的意外复杂性,因为索引对象的行为可能与您期望的不同。

即使你要嵌入一个对象,_id也是一个奇怪的名字 - _id只是一流数据库文档的保留名称。

答案 2 :(得分:2)

一对一的关系

1对1关系是每个项目恰好对应于另一个项目的关系。 e.g:

  • 员工有简历,反之亦然
  • 建筑物有平面图,反之亦然
  • 患者有病史,反之亦然

    
    //employee
    {
    _id : '25',
    name: 'john doe',
    resume: 30
    }
    
    //resume
    {
    _id : '30',
    jobs: [....],
    education: [...],
    employee: 25
    }
    
    

我们可以通过拥有一组员工和一系列简历并让员工通过链接指向简历来为员工 - 简历关系建模,我们的ID对应ID在简历集合中。或者,如果我们愿意,我们可以链接另一个方向,我们在简历集合中有一个员工密钥,它可能指向员工本身。或者如果我们想要,我们可以嵌入。因此,我们可以获取整个简历文档,我们可以将其嵌入员工集合中,反之亦然。

此嵌入取决于应用程序如何访问数据以及访问数据的频率。我们需要考虑:

  • 访问频率
  • 物品的大小 - 一直在增长的东西和不增长的东西。因此,每次我们向文档添加内容时,都需要在集合中移动文档。如果文档大小超过16 MB,这几乎不可能。
  • 数据的原子性 - MongoDB中没有任何事务,对单个文档进行原子操作。因此,如果我们知道我们无法承受任何不一致,并且我们希望能够一直更新整个员工和简历,我们可能会决定将它们放在同一个文档中并以一种方式嵌入它们或者其他,以便我们可以立即更新所有。

答案 3 :(得分:1)

在mongodb中,我们建议您尽可能嵌入文档,尤其是在您拥有一对一关系的情况下。

为什么呢?你不能在你的查询中使用原子连接操作(即使它不是你的主要关注点)(不是主要原因)。但最好的理由是每个join-op(理论上)都需要大约20毫秒的硬搜索。嵌入你的子文档只需要1次硬搜索。

我认为最适合您的db-schema只是为所有实体使用id

{
    _id : ObjectId("547d5c1b1e42bd0423a75781"),
    userInfo : 
    {
        "name" : "john", 
        "email" : "test@localhost.com", 
        "phone" : "01022223333",
    },
    customerInfo : 
    {
        "birthday" : "1983-06-28", 
        "zipcode" : "12345", 
        "address" : "1, Main Street", 
    },
    staffInfo : 
    {
        ........
    }
}

现在,如果您只想要 userinfo ,可以使用

db.users.findOne({_id : ObjectId("547d5c1b1e42bd0423a75781")},{userInfo : 1}).userInfo;

它只会为您提供 userInfo

/* 0 */
{
    "name" : "john",
    "email" : "test@localhost.com",
    "phone" : "01022223333"
}

如果你只想要** customerInfo **,你可以使用

db.users.findOne({_id : ObjectId("547d5c1b1e42bd0423a75781")},{customerInfo : 1}).customerInfo;

它只会为您提供 customerInfo

/* 0 */
{
    "birthday" : "1983-06-28",
    "zipcode" : "12345",
    "address" : "1, Main Street"
}

等等。

此架构具有最小的硬往返,实际上您正在使用mongodb基于文档的功能,并且可以实现最佳性能。