【问题标题】:How to tag documents in MongoDB?如何在 MongoDB 中标记文档?
【发布时间】:2018-01-23 07:03:52
【问题描述】:

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

我的第一个想法是为每个文档创建一个名为“标签”的属性。 好吧,在这种情况下,我们有类似的东西:

{
_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"
}

也就是说,我们有一个单独的文档,代表每个用户的标签。

又酷又干净,对吧?

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

  1. 小问题:我们返回到我不再喜欢但在某些情况下接受的 SQL 逻辑。
  2. 大(对我而言)问题:如何通过个人标签搜索联系人?在这种情况下,我们有一个很好的 'JOIN' 问题,MongoDB 使用 $lookup 很好地解决了这个问题。 对于 10000、20000 甚至 500000 个文档,“解决得很好”。但由于我想确保未来有良好的表现,我认为有 10000000 个联系人。因此,正如我最近研究的那样,$lookup 适用于 Universe 的“一小部分”,即使使用索引,执行此搜索也需要很长时间。

如何解决这个挑战?

谢谢大家

【问题讨论】:

    标签: mongodb collections tags lookup


    【解决方案1】:

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

    此答案的其余部分假定大小估计以及您对每个联系人可能的标签和用户数量的了解使得大小限制有效。在此基础上,您表示了对连接性能的具体关注......

    但由于我想确保未来有良好的表现,我认为有 10000000 个联系人。因此,正如我最近研究的那样,$lookup 对宇宙的“一小部分”很有效,即使有索引,这个搜索也需要很长时间才能执行。

    您是否尝试过衡量这种性能?为contactstags 生成种子文档,然后保留它们的变体,然后使用 $lookup 运行查询并测量性能。您可以针对一些基准测试执行此操作,例如:

    • 1000 个联系人和 10000 个标签
    • 100,000 个联系人和 1,000,000 个标签
    • 1,000,000 个联系人和 10,000,000 个标签
    • 10,000,000 个联系人和 100,000,000 个标签

    运行基准测试时,您还可以使用explain() 了解 MongoDB 内部发生了什么。

    您可能会发现性能是可以接受的,只有您知道这一点,因为您了解系统用户对性能的期望。

    最后一点,如果这里的用例是给定用户想要找到他们所有的联系人和标签,那么这个可以通过“客户端连接”来处理,即两个查询(1 ) 获取"userId" : "..." 的标签和 (2) 查找这些标签引用的联系人。根据您的用例,这可能比服务器端加入(又名 $lookup)的性能更高。

    【讨论】:

      猜你喜欢
      • 2019-02-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多