MongoDB多对多关联

你将如何与MongoDB进行多对多的关联?

例如; 假设你有一个Users表和一个Roles表。 用户有很多angular色,angular色有很多用户。 在SQL的土地上,你会创build一个UserRoles表。

Users: Id Name Roles: Id Name UserRoles: UserId RoleId 

在MongoDB中如何处理同样的关系?

根据您的查询需求,您可以将所有内容放在用户文档中:

 {name:"Joe" ,roles:["Admin","User","Engineer"] } 

要获得所有的工程师,请使用:

 db.things.find( { roles : "Engineer" } ); 

如果您想要在单独的文档中维护angular色,则可以将文档的_id包含在angular色数组中,而不是名称中:

 {name:"Joe" ,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"] } 

并build立如下angular色:

 {_id:"6c6793300334001000000006" ,rolename:"Engineer" } 

根据我们多年来使用RDBMS的经验,我没有尝试进行build模,而是通过对读取用例进行优化,使用MongoDB,Redis和其他NoSQL数据存储库对文档存储库解决schemebuild模,同时考虑primefaces写入操作需要被写入用例支持。

例如,“angular色中的用户”域的用法如下:

  1. angular色 – 创build,阅读,更新,删除,列出用户,添加用户,删除用户,清除所有用户,索引用户或类似支持“用户在angular色”(操作像一个容器+自己的元数据)。
  2. 用户 – 创build,读取,更新,删除(CRUD操作就像一个独立的实体)

这可以build模为以下文档模板:

 User: { _id: UniqueId, name: string, roles: string[] } Indexes: unique: [ name ] Role: { _id: UniqueId, name: string, users: string[] } Indexes: unique: [ name ] 

为了支持高频用途,比如User实体的Role-related特性,User.Roles被有意的非规范化,存储在用户以及具有重复存储的Role.Users上。

如果在文本中不明显,但这是使用文档存储库时所鼓励的思维types。

我希望这有助于缩小与操作的阅读方面的差距。

对于写入方面,鼓励的是根据primefaces写入进行build模。 例如,如果文档结构需要获取锁,则更新一个文档,然后更新另一个文档(可能还有更多文档),然后释放该锁,可能该模型失败。 仅仅因为我们可以构build分布式锁并不意味着我们应该使用它们。

对于“angular色中的用户”模型,拉伸我们的primefaces写入避免锁的操作是从angular色添加或删除用户。 无论哪种情况,成功的操作都会导致更新单个用户和单个angular色文档。 如果失败了,很容易清理。 这是工作单元模式在使用文档存储库时出现的很多原因之一。

真正延伸我们的primefaces写入避免锁的操作是清除angular色,这将导致许多用户更新从User.roles数组中删除Role.name。 这种明确的操作通常是不鼓励的,但是如果需要的话可以通过命令操作来实现:

  1. 从Role.users获取用户名称列表。
  2. 迭代步骤1中的用户名,从User.roles中删除angular色名称。
  3. 清除Role.users。

在最有可能在步骤2中发生的问题的情况下,由于可以使用来自步骤1的同一组用户名来恢复或继续,因此回滚很容易。

我刚刚偶然发现了这个问题,尽pipe这是一个老问题,但我认为在给出的答案中增加一些没有提到的可能性是有用的。 另外,在过去的几年里,事情已经发生了一些变化,所以值得强调的是,SQL和NoSQL正在相互靠拢。

其中一位评论者提出了“数据是关系型,使用关系型”的谨慎态度。 然而,这个评论在关系世界中才有意义,在这个世界里,模式总是在应用之前出现。

RELATIONAL WORLD: 结构数据>编写应用程序来获取它
NOSQL WORLD: devise应用程序>相应地组织数据

即使数据是关系数据,NoSQL仍然是一种select。 例如,一对多的关系根本没有问题,在MongoDB文档中被广泛的覆盖

解决2010年问题的2015年解决scheme

自从这个问题发布以来,已经有人认真地尝试将noSQL更接近SQL。 由加利福尼亚大学的Yannis Papakonstantinou领导的研究小组一直在研究FORWARD ,这是SQL ++的一个实现,它可能很快就成为像这里发布的那样持久性问题的解决scheme。

在更实用的层面上,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 

N1QL允许大部分(如果不是全部)SQL操作(包括聚合,过滤等)。

不是那么新的混合解决scheme

如果MongoDB仍然是唯一的select,那么我想回到我的观点,应用程序应该优先于数据结构。 没有一个答案提到混合embedded,即将大多数查询数据embedded到文档/对象中,并且为less数情况保留引用。

例如:can信息(angular色名称除外)是否等待? 通过不请求任何用户不需要的东西,可以更快地引导应用程序?

如果用户login并且他/她需要查看所有他/她所属的angular色的所有选项,则可能是这种情况。 然而,用户是一个“工程师”,这个angular色的选项很less使用。 这意味着应用程序只需要显示一个工程师的选项,以防他/她想点击它们。

这可以通过一个文档来告诉应用程序在开始时(1)用户属于哪个angular色,以及(2)从哪里获得关于与特定angular色关联的事件的信息。

  {_id: ObjectID(), roles: [[“Engineer”, “ObjectId()”], [“Administrator”, “ObjectId()”]] } 

或者,甚至更好地,索引angular色集合中的role.name字段,并且您可能不需要embeddedObjectID()。

另一个例子:关于所有angular色请求的信息所有的时间?

也可能是用户login仪表板,90%的时间执行链接到“工程师”angular色的任务。 混合embedded可以完成这个特定的angular色,只保留其余的参考。

 {_id: ObjectID(), roles: [{name: “Engineer”, property1: value1, property2: value2 }, [“Administrator”, “ObjectId()”] ] } 

无模式化不仅仅是NoSQL的一个特性,在这种情况下可能是一个优势。 在用户对象的“angular色”属性中嵌套不同types的对象是完全有效的。

如果员工和公司是实体对象,则尝试使用以下模式:

 employee{ //put your contract to employee contracts:{ item1, item2, item3,...} } company{ //and duplicate it in company contracts:{ item1, item2, item3,...} }