"Mongodb多对多关联"
"Mongodb多对多关联"
如何使用MongoDB进行多对多关联?
例如;假设您有一个用户表和一个角色表。用户拥有多个角色,角色也拥有多个用户。在SQL领域中,您需要创建一个UserRoles表。
Users: Id Name Roles: Id Name UserRoles: UserId RoleId
在MongoDB中如何处理同样的关系?
与按照我们多年使用关系型数据库的经验进行建模不同,我发现使用MongoDB,Redis和其他NoSQL数据存储优化读用例并考虑写用例需要支持的原子写操作更容易建模文档存储库解决方案。
例如,“用户角色”域的用途如下:
- 角色—创建,读取,更新,删除,列出用户,添加用户,删除用户,清除所有用户,用户索引或类似支持“用户是否在角色中”(操作类似于容器+自身元数据)。
- 用户—创建,读取,更新,删除(CRUD操作类似于自由实体)
这可以建模为以下文档模板:
User: { _id: UniqueId, name: string, roles: string[] } Indexes: unique: [ name ] Role: { _id: UniqueId, name: string, users: string[] } Indexes: unique: [ name ]
为了支持高频使用,例如从User实体中的角色相关功能,User.Roles有意进行了去规范化,同时在User上和Role.Users上具有重复存储。
如果在文本中不显然,但使用文档存储库时鼓励的是这种思维方式。
我希望这有助于弥合关于操作读取方面的差距。
对于写入方面,鼓励根据原子写入进行建模。例如,如果文档结构要求获得锁定,更新一个文档,然后另一个文档,可能还有更多文档,然后释放锁定,那么可能模型已失败。仅仅因为我们可以构建分布式锁并不意味着我们必须使用它们。
对于用户角色模型,伸展我们的原子写避免锁定的操作是添加或删除用户的角色。在任一情况下,成功的操作都会导致更新单个用户和单个角色文档。如果出现问题,很容易进行清理。这是使用文档存储库时经常出现“工作单元”模式的原因之一。
真正伸展我们原子写避免锁定的操作是清除角色,这将导致许多用户更新以从用户角色数组中删除角色名称。通常不鼓励进行此操作,但如果需要可以通过排序操作实现:
- 从Role.users获取用户名列表。
- 从步骤1中迭代用户名称,从User.roles中删除角色名称。
- 清除Role.users。
在出现问题的情况下,最有可能发生在步骤2中,回滚很容易,因为可以使用与步骤1中相同的一组用户名来恢复或继续。
根据您的查询需求,您可以将所有内容放在用户文档中:
{name:"Joe" ,roles:["Admin","User","Engineer"] }
如果您想获得所有的工程师,请使用:
db.things.find( { roles : "Engineer" } );
如果您想要将角色存储在独立的文档中,那么您可以在角色数组中包含文档的_id而不是名称:
{name:"Joe" ,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"] }
并设置角色如下:
{_id:"6c6793300334001000000006" ,rolename:"Engineer" }