Jos*_*ose 128 many-to-many associations mongodb
你会如何与MongoDB进行多对多的关联?
例如; 假设您有一个Users表和一个Roles表.用户有很多角色,角色有很多用户.在SQL中,您将创建一个UserRoles表.
Users:
Id
Name
Roles:
Id
Name
UserRoles:
UserId
RoleId
Run Code Online (Sandbox Code Playgroud)
MongoDB中如何处理相同类型的关系?
die*_*ikh 88
根据您的查询需求,您可以将所有内容放在用户文档中:
{name:"Joe"
,roles:["Admin","User","Engineer"]
}
Run Code Online (Sandbox Code Playgroud)
要获得所有工程师,请使用:
db.things.find( { roles : "Engineer" } );
Run Code Online (Sandbox Code Playgroud)
如果要将角色维护在单独的文档中,则可以在roles数组中包含文档的_id而不是名称:
{name:"Joe"
,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"]
}
Run Code Online (Sandbox Code Playgroud)
并设置如下角色:
{_id:"6c6793300334001000000006"
,rolename:"Engineer"
}
Run Code Online (Sandbox Code Playgroud)
pae*_*gun 30
我没有尝试根据我们多年的RDBMS经验进行建模,而是通过优化读取用例,同时考虑到原子,使用MongoDB,Redis和其他NoSQL数据存储来建模文档存储库解决方案要容易得多.编写需要由写用例支持的操作.
例如,"角色中的用户"域的使用如下:
这可以建模为以下文档模板:
User: { _id: UniqueId, name: string, roles: string[] }
Indexes: unique: [ name ]
Role: { _id: UniqueId, name: string, users: string[] }
Indexes: unique: [ name ]
Run Code Online (Sandbox Code Playgroud)
为了支持高频用途,例如来自User实体的与角色相关的功能,User.Roles被有意地非规范化,存储在用户以及具有重复存储的Role.Users上.
如果在文本中不是很明显,但这是在使用文档存储库时鼓励的思维类型.
我希望这有助于缩小与业务的阅读方面的差距.
对于写入方,鼓励的是根据原子写入进行建模.例如,如果文档结构需要获取锁,更新一个文档,然后更新另一个文档,可能还有更多文档,然后释放锁,则模型可能失败.仅仅因为我们可以构建分布式锁并不意味着我们应该使用它们.
对于角色中的用户模型,扩展我们的原子写入避免锁定的操作是在角色中添加或删除用户.在任何一种情况下,成功的操作都会导致单个用户和单个角色文档被更新.如果出现故障,很容易进行清理.这就是工作单元模式在使用文档存储库时出现的原因之一.
真正延伸我们的原子写入避免锁定的操作是清除一个角色,这将导致许多用户更新从User.roles数组中删除Role.name.通常不鼓励这种清除操作,但如果需要可以通过订购操作来实现:
在最有可能在步骤2中发生的问题的情况下,回滚很容易,因为可以使用来自步骤1的同一组用户名来恢复或继续.
cor*_*opy 14
我刚刚偶然发现了这个问题,虽然这是一个旧问题,但我认为在答案中添加一些未提及的可能性会很有用.此外,在过去的几年里,事情已经发生了变化,所以值得强调的是SQL和NoSQL正在相互靠近.
其中一位评论者提出了明智的警示态度,即"如果数据是关系的,则使用关系".但是,该注释仅在关系世界中有意义,其中模式总是在应用程序之前出现.
关系世界:结构数据>编写应用程序以获取它
NOSQL WORLD:设计应用程序>相应地构造数据
即使数据是关系型的,NoSQL仍然是一种选择.例如,一对多关系完全没有问题,并且在MongoDB文档中广泛涉及
自从这个问题发布以来,已经有一些认真的尝试让noSQL更接近SQL.由加利福尼亚大学圣地亚哥分校的Yannis Papakonstantinou领导的团队一直致力于FORWARD,这是一个SQL ++的实现,很快就可以解决像这里发布的问题.
在更实际的层面上,Couchbase 4.0的发布意味着,你可以第一次在NoSQL中进行原生JOIN.他们使用自己的N1QL.这是JOIN
他们的教程中的一个示例:
SELECT usr.personal_details, orders
FROM users_with_orders usr
USE KEYS "Elinor_33313792"
JOIN orders_with_users orders
ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END
Run Code Online (Sandbox Code Playgroud)
N1QL允许大多数(如果不是全部)SQL操作,包括聚合,过滤等.
如果MongoDB仍然是唯一的选择,那么我想回到我的观点,即应用程序应该优先于数据结构.没有一个答案提到混合嵌入,其中大多数查询数据嵌入在文档/对象中,并且针对少数情况保留了引用.
示例:可以将信息(角色名称除外)等待吗?通过不请求用户不需要的任何内容,可以更快地引导应用程序吗?
如果用户登录并且他/她需要查看他/她所属的所有角色的所有选项,则可能是这种情况.但是,用户是"工程师",很少使用此角色的选项.这意味着应用程序只需要显示工程师的选项,以防他/她想要点击它们.
这可以通过文档来实现,该文档在开始时告诉应用程序(1)用户所属的角色以及(2)从何处获得关于链接到特定角色的事件的信息.
{_id: ObjectID(),
roles: [[“Engineer”, “ObjectId()”],
[“Administrator”, “ObjectId()”]]
}
Run Code Online (Sandbox Code Playgroud)
或者,更好的是,索引roles集合中的role.name字段,您也可能不需要嵌入ObjectID().
另一个例子:是否始终要求所有角色的信息?
也可能是用户登录仪表板并且90%的时间执行链接到"工程师"角色的任务.可以完全针对该特定角色进行混合嵌入,并仅为其余角色保留参考.
{_id: ObjectID(),
roles: [{name: “Engineer”,
property1: value1,
property2: value2
},
[“Administrator”, “ObjectId()”]
]
}
Run Code Online (Sandbox Code Playgroud)
无模式不仅仅是NoSQL的一个特征,在这种情况下它可能是一个优势.在用户对象的"角色"属性中嵌套不同类型的对象是完全有效的.
如果员工和公司是实体对象,请 尝试使用以下模式:
employee{
//put your contract to employee
contracts:{ item1, item2, item3,...}
}
company{
//and duplicate it in company
contracts:{ item1, item2, item3,...}
}
Run Code Online (Sandbox Code Playgroud)