我需要标记集合中的文档,我们将其称为“联系人”。
我的第一个想法是为每个文档创建一个名为“标签”的属性。 好吧,在这种情况下,我们有这样的东西:
{
_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']},
{.....................................................}
{.....................................................}
{......................................................}
]
}
但是,如果我们有数百万用户怎么办?在这种情况下,据我所知,我们对每个文档有 16 毫克的限制......
此时,担心我的应用程序的 future 增长,我决定 创建一个名为“标签”的漂亮分离集合,其中包含类似于以下内容的文档:
{
"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 个文档“解析良好”。但由于我想确保 future 有良好的表现,我考虑了 10000000 个联系人。因此,正如我最近研究的那样,$lookup 对于宇宙的“一小部分”效果很好,即使使用索引,执行此搜索也将花费大量时间。
如何解决这一挑战?
谢谢大家
最佳答案
如果您的使用情况是每个联系人的用户数量
X 标签数量/大小
(加上联系人
中的任何其他数据) > document)可能会让您接近 16MB 文档大小限制,那么将标签存储在单独的集合中似乎是有效的。但在你走这条路之前,你确定这有可能吗?您是否尝试过创建联系人文档,看看每个联系人有多少个标签、多少个用户将使您接近 16MB 的限制。如果答案意味着您不太可能接触到许多用户和/或标签,那么您的担忧可能只是理论上的,您可以考虑坚持使用最简单的解决方案,即将用户特定的标签嵌入联系人
.
此答案的其余部分假设大小估计以及您对每个联系人的可能标签和用户数量的了解使得大小限制有效。在此基础上,您提出了对连接性能的具体关注......
But as I want to ensure a good performance in the future, I think about 10000000 contacts. So, as I researched recently, the $lookup works well for a "small part" of universe and, even with indexes, this search would take a lot of time to be executed.
您是否尝试过衡量这种性能?为联系人
和标签
生成种子文档,然后保留它们的变体,然后使用$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/