重做这个答案,因为原始答案由于阅读不正确而导致关系错误。
问题= {代码:“asdf-11”,标题:“asdf”,记者:{用户名:“qwer”,角色:“经理”}}
至于嵌入有关票证的用户(创建者)的一些重要信息是否是一个明智的决定,取决于系统的具体情况。
您是否让这些用户能够登录并报告他们发现的问题?如果是这样,那么您可能希望将该关系考虑到用户集合中。
另一方面,如果不是这种情况,那么您可以轻松摆脱这种模式。我在这里看到的一个问题是,如果你想联系记者并且他们的工作角色已经改变,那就有点尴尬了;然而,这是一个现实世界的困境,而不是数据库的困境。
由于子文档代表与记者的单一一对一关系,因此您也不应该遭受我原始答案中提到的碎片问题。
这种模式有一个明显的问题,那就是重复更改重复数据(规范化形式的东西)。
让我们举个例子。想象一下,你遇到了我之前谈到的现实世界的两难境地,一个被叫的用户Nigel
希望他的角色从现在开始反映他的新工作职位。这意味着您必须更新Nigel
记者所在的所有行并将其更改role
为该新位置。对于 MongoDB,这可能是一个冗长且耗费资源的查询。
再次自相矛盾,如果每个用户可能只有 100 张票(也就是可管理的东西),那么更新操作可能不会太糟糕,事实上,数据库很容易管理;另外,由于文档缺乏移动(希望如此),这将是一个完全到位的更新。
因此,是否应该嵌入这在很大程度上取决于您的查询和文档等,但是,我会说这种模式不是一个好主意;特别是由于在许多根文档中重复更改数据。从技术上讲,是的,你可以侥幸逃脱,但我不会尝试。
相反,我会将两者分开。
如果我在文档中有对象(子文档),我可以在一个查询中更新它们吗?
就像我原来的答案中的关系风格一样,是的,很容易。
例如,让我们更新Nigel
to的角色MD
(如前所述)并将工单状态更改为已完成:
db.tickets.update({'reporter.username':'Nigel'},{$set:{'reporter.role':'MD', status: 'completed'}})
因此,在这种情况下,单个文档模式确实使 CRUD 更容易。
需要注意的一件事,源于您的英语,您不能使用位置运算符来更新根文档下的所有子文档。相反,它只会更新第一个找到的。
再次希望这是有道理的,我没有遗漏任何东西。高温高压
原始答案
在这里,我有一个与该问题相关的用户)。我应该创建另一个文档“用户”并通过其 ID 在“问题”文档中引用它(如在关系数据库中),还是应该将所有用户的数据留在子文档中?
这是一个相当大的问题,在继续之前需要一些背景知识。
首先要考虑的是问题的大小:
issue = {code:"asdf-11", title:"asdf", reporter:{username:"qwer", role:"manager"}}
不是很大,并且由于您不再需要reporter
信息(将在根文档上),它可能会更小,但是,问题从来没有那么简单。例如,如果您查看 MongoDB JIRA:https ://jira.mongodb.org/browse/SERVER-9548 (作为证明我观点的随机页面),“票证”的内容实际上可能相当可观。
从嵌入票证中获得真正好处的唯一方法是,如果您可以将所有用户信息存储在一个 16 MB 的连续存储块中,这是 BSON 文档的最大大小(由mongod
当前规定)。
我认为您无法将所有票证存储在单个用户下。
即使您将票缩小到代码、标题和描述,您仍然可能会遭受由 MongoDB 中的文档定期更新和更改引起的“瑞士奶酪”问题,就像以前一样:http://www .10gen.com/presentations/storage-engine-internals是我的意思的一个很好的参考。
当用户向他们的根用户文档添加多个票证时,您通常会看到这个问题。门票本身也会发生变化,但可能不会剧烈或频繁地发生变化。
当然,您可以通过使用 2 大小分配的幂来稍微解决这个问题: http: //docs.mongodb.org/manual/reference/command/collMod/#usePowerOf2Sizes将完全按照它在锡上所说的那样做。
好的,假设,如果你只有code
然后title
是的,你可以将票作为子文档存储在 root 用户中而不会出现太多问题,但是,这归结为赏金受让人没有提到的细节。
如果我在文档中有对象(子文档),我可以在一个查询中更新它们吗?
是的,很容易。这是通过嵌入变得更容易的一件事。您可以使用如下查询:
db.users.update({user_id:uid,'tickets.code':'asdf-1'}, {$set:{'tickets.$.title':'Oh NOES'}})
但是,请注意,您一次只能使用位置运算符更新一个子文档。因此,这意味着您无法在单个原子操作中将单个用户的所有票证日期更新为未来 5 天。
至于添加新票,这很简单:
db.users.update({user_id:uid},{$push:{tickets:{code:asdf-1,title:"Whoop"}}})
所以是的,您可以很简单地根据您的查询,在一次调用中更新整个用户数据。
这是一个相当长的答案,所以希望我没有错过任何东西,希望它有所帮助。