我需要在集合中标记文档,我们称之为“联系人”。
我的第一个想法是为每个文档创建一个称为“标签”的属性。
好吧,在这种情况下,我们有以下内容:
{
_id:'1',
contact_name:'Asya Kamsky',
tags:['mongodb', 'maths', 'travels']
}
现在,假设我们有一些用户希望在“联系人”中标记任何文档。
如果我们决定保存每个文档的标签属性,因为标签是个人标签,我们需要为每个标签使用userId。
因此我们的文档将是这样的(或不是):
{
_id:'1',
contact_name:'Asya Kamsky',
tags:[
{userId:'alex',tags:['mongodb', 'maths', 'travels']},
{userId:'eric',tags:['databases', 'friends', 'japan']},
]
}
现在,让我们复杂一点。假设我们有很多用户,每个用户都想用他的个人标签来标记文档。
怎么处理呢?
好的,我们可以为每个文档创建数千个标签:
{
_id:'1',
contact_name:'Asya Kamsky',
tags:[
{userId:'alex',tags:['mongodb', 'maths', 'travels']},
{userId:'eric',tags:['databases', 'friends', 'japan']},
{.....................................................}
{.....................................................}
{......................................................}
]
}
但是,如果我们有数百万的用户呢?我知道在这种情况下,每个文档的限制为16mg。
此时,由于担心我的应用程序的将来增长,我决定
创建一个名为“ tags”的分离好的集合,其中包含类似于以下内容的文档:
{
"contact_name" : "Asya Kamsky",
"useriId" : "alex",
"tags" : ['mongodb', 'maths', 'travels'],
"timestamp" : "2017-08-08 14:33:28"
},
{
"contact_name" : "Asya Kamsky",
"useriId" : "eric",
"tags" : ['databases', 'friends', 'japan'],
"timestamp" : "2017-08-08 14:33:28"
}
也就是说,我们有一个单独的文档,分别代表每个用户的标签。
凉爽吧?
好吧,在这种情况下,我们面临两个问题:
次要问题:我们返回到我不再喜欢的SQL逻辑,但在某些情况下我接受了。
大(对我而言)问题:如何通过“个人”标签搜索联系人?在这种情况下,我们有一个很好的“ JOIN”问题,MongoDB使用$ lookup可以很好地解决这个问题。
可以很好地解析10000、20000甚至500000个文档。但是由于我想确保将来有良好的表现,我认为大约有1000万个联系人。因此,正如我最近研究的那样,$ lookup对于Universe的“一小部分”非常有效,即使使用索引,此搜索也将花费大量时间来执行。
如何解决这一挑战?
谢谢大家
最佳答案
如果您的用法使得每个联系人number of users
X number/size of tags
(加上contacts
文档中的任何其他数据)很可能使您接近16MB的文档大小限制,则将标签存储在单独的集合中似乎是有效的。但是在走那条路线之前,您确定这可能吗?您是否尝试过创建联系文档以查看有多少标签,每个联系人有多少用户使您接近16MB的限制。如果答案暗示了许多用户和/或标签,而这些标签您根本不可能接触到,那么您的顾虑可能是严格的理论上的,您可以考虑采用最简单的解决方案,即将用户特定的标签嵌入contacts
中。
该答案的其余部分假定大小估计以及您对每个联系人可能的标签和用户数量的了解,使得大小约束有效。在此基础上,您陈述了对联接性能的特定关注...
但是由于我想确保将来有良好的表现,我认为大约有1000万个联系人。因此,正如我最近研究的那样,$ lookup对于Universe的“一小部分”非常有效,即使使用索引,此搜索也将花费大量时间来执行。
您是否尝试过评估这种效果?生成contacts
和tags
的种子文档,然后保留它们的变体,然后使用$ lookup运行查询并评估性能。您可以针对一些基准进行此操作,例如:
1,000个联系人和10,000个标签
100,000个联系人和1,000,000个标签
1,000,000个联系人和10,000,000个标签
10,000,000个联系人和100,000,000个标签
在运行基准测试时,您还可以使用explain()
来了解MongoDB内部的情况。
您可能会发现性能是可以接受的,只有您知道这一点,因为您了解系统用户对性能的期望。
最后一点,如果这里的用例是给定用户想要查找其所有联系人和标签,则可以使用“客户端加入”来处理,即两个查询(1)以获取"userId" : "..."
和(2)查找那些标签引用的联系人。根据您的用例,这可能比服务器端联接(也称为$ lookup)更高效。
关于mongodb - 如何在MongoDB中标记文档?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45691495/