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色中的用户”域的用法如下:
- angular色 – 创build,阅读,更新,删除,列出用户,添加用户,删除用户,清除所有用户,索引用户或类似支持“用户在angular色”(操作像一个容器+自己的元数据)。
- 用户 – 创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。 这种明确的操作通常是不鼓励的,但是如果需要的话可以通过命令操作来实现:
- 从Role.users获取用户名称列表。
- 迭代步骤1中的用户名,从User.roles中删除angular色名称。
- 清除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,...} }