我有两个MongoDB集合user
和customer
,它们是一对一的关系。我是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)?
{
"_id" : ObjectId("547d916a660729dd531f145d"),
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street",
"user" : ObjectId("547d5c1b1e42bd0423a75781")
}
{
"_id" : ObjectId("547d916a660729dd531f145d"),
"birthday" : "1983-06-28",
"zipcode" : "12345",
"address" : "1, Main Street",
"user" : {
"_id" : ObjectId("547d5c1b1e42bd0423a75781")
}
}
答案 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
在简历集合中。或者,如果我们愿意,我们可以链接另一个方向,我们在简历集合中有一个员工密钥,它可能指向员工本身。或者如果我们想要,我们可以嵌入。因此,我们可以获取整个简历文档,我们可以将其嵌入员工集合中,反之亦然。
此嵌入取决于应用程序如何访问数据以及访问数据的频率。我们需要考虑:
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基于文档的功能,并且可以实现最佳性能。