如何在MongoDB中标记文档?

时间:2017-08-15 10:59:11

标签: mongodb collections tags lookup

我需要在集合中标记文档,让我们称之为“联系人”。

我的第一个想法是创建一个名为" tags"对于每个文件。 那么,在这种情况下,我们有类似的东西:

{
_id:'1',
contact_name:'Asya Kamsky',
tags:['mongodb', 'maths', 'travels']
}

现在,我们假设我们的用户想要在'通讯录中标记任何文档。

如果我们决定为每个文档保存tags属性,因为标签是个人的,我们需要为每个标签使用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毫克的限制....

此时,我决定担心我的应用程序未来的增长 创建一个名为'标签的漂亮的分隔集合'这将包含类似于:

的文件
{
    "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"
}

我们有一个单独的文件,代表每个用户的标签。

清凉干净吧?

嗯,在这种情况下,我们面临两个问题:

  1. 小问题:我们回到了我不再喜欢的SQL逻辑,但在某些情况下我接受了。
  2. Big(对我来说)问题:如何通过PERSONAL标签搜索联系人?在这种情况下,我们有一个很好的加入' MongoDB使用$ lookup很好地解决的问题。 "解决得很好"适用于10000,20000甚至500000个文档。但是,由于我想确保未来的良好表现,我认为有大约10000000个联系人。所以,正如我最近研究的那样,$ lookup适用于"小部分"即使使用索引,这种搜索也会花费大量时间来执行。
  3. 如何解决这一挑战?

    全部谢谢

1 个答案:

答案 0 :(得分:0)

如果您的使用情况是每个联系人number of users X number/size of tags(加上contacts文档中的其他任何数据)可能会使您接近16MB的文档大小限制将标签存储在单独的集合中似乎是有效的。但是在你走这条路之前你确定这可能吗?您是否尝试创建联系人文档以查看有多少标记,每个联系人有多少用户可以使您接近16MB限制。如果答案意味着您不太可能达到的许多用户和/或标签,那么您的担忧可能是严格的理论问题,您可以考虑坚持使用最简单的解决方案,即在contacts内嵌入用户特定的标签。

本答案的其余部分假定大小估计值以及您对每个联系人可能的标签数量和用户数量的了解使得大小限制有效。在此基础上,您对加入表现提出了特别的关注......

  

但是,由于我想确保未来的良好表现,我认为有10000000个联系人。因此,正如我最近研究的那样,$ lookup适用于Universe的“小部分”,即使使用索引,这种搜索也会花费大量时间来执行。

您是否尝试过测量此性能?为contactstags生成种子文档,然后保留这些文档的变体,然后使用$ 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)。