【问题标题】:MongoDB Array or Separate collectionMongoDB 数组或单独的集合
【发布时间】:2014-02-25 02:29:55
【问题描述】:

我有一个用户集合。 每个用户可能有: - 大量关注者(100K+)并且可能关注大量其他用户。 - 收藏夹的大列表 - 查看的大量项目列表

我看到了模式的 2 设计。关于查询,我需要找到用户关注的人 我还需要知道给定用户的收藏夹、观看列表。 所有列表(关注者、关注者、收藏夹必须具有唯一条目

我试图通过 Google 查找类似的问题或主题,但找不到任何内容。

MongoDB 能否处理像这样的大型数组,或者我应该采用设计方法 2,将映射存储在单独的集合中,这样我就可以拥有无​​限的映射数量?

感谢您的宝贵意见。

我选择选项 2,因为它允许我拥有无限数量的映射。 但在我走这条路之前,我想检查一下是否会有我不想要的问题。

从一种设计转移到另一种设计会很昂贵。

Design 1 (EMBEDDED ARRAY TO STORE MAPPINGS):
[
{
  user: bob, //(key)
  followers: ["Alex", "john", "steve", "mark", ... 200K+ entries]
  following: ["Mila", "mark", "Bill", "Joe", ... 100K+ entries]
  favorites: [ObjectI(1), ObjectId(2),...5K+ entries]
  watched: [ObjectI(4), ObjectId(5),...100K+ entries]
},
{
  user: Nick, //(key)
  followers: [bob", "kery", "Jery", "Tom", ... 200K+ entries]
  following: ["Tim", "Shane", "Sally", "Joe", ... 100K+ entries]
  favorites: [ObjectI(4), ObjectId(5),...5K+ entries]
  watched: [ObjectI(2), ObjectId(9),...100K + entries]
}
]

设计 2(存储映射的单独集合)

user_followers collection:
[
 { user: bob, follower: "Alex" }, //key: (user, follower)
 { user: bob, follower: "john"}, 
 { user: bob, follower: "steve"}, 
 { user: bob, follower: "mark"}
  ... 200K+ entries
]

user_following collection:
[
 { user: bob, following: "Mila"},  //key (user, following)
 { user: bob, following: "mark"},
 { user: bob, following: "Bill"}, 
 { user: bob, following: "Joe"},
 ... 100K+ entries
]

user_favorites collection:
[
 { user: bob, favorite: ObjectId(1)},
 { user: bob, favorite: ObjectId(3)},
 { user: bob, favorite: ObjectId(6)},
 ... 5k entries
},

【问题讨论】:

  • 看来使用常规关系数据库会更好。

标签: mongodb


【解决方案1】:

MongoDB 能否处理像这样的大型数组,或者我应该采用设计方法 2,将映射存储在单独的集合中,这样我就可以拥有无​​限的映射数量?

在 MongoDB 中,一个文档可以是at most 16 MB。对于您的第一个设计,您可能会达到我认为的极限。

关于第二个设计,在我看来 user_followersuser_following 集合只是复制了相同的数据:如果 bob 正在关注 martha,那么 bob 是 martha 的追随者,所以你可以将这两个集合合并到一个带有 { followed: 'martha', follower: 'bob' } 之类的条目

更新

cmets 中有关于如何处理双向关系或查询索引的问题。

给定两个用户 bob 和 martha,他们可以没有关系,或者 bob 跟随 martha,或者 martha 跟随 bob,或者 bob 和 martha 互相跟随,即三种不同的可能关系。

现在对于 bob 跟随 martha 的情况,followers 集合将是

[
  {
    followed: 'martha',
    follower: 'bob'
  }
]

对于玛莎跟随鲍勃的情况,它会是

[
  {
    followed: 'bob',
    follower: 'martha'
  }
]

当两个人互相跟随时

[
  {
    followed: 'martha',
    follower: 'bob'
  }, {
    followed: 'bob',
    follower: 'martha'
  }
]

这种设计唯一昂贵的操作在设计 1 和 2 中也是昂贵的,原因相同:我们需要隔离两个集合之间的公共元素;该操作正在寻找双向关系(例如 bob 和 martha 互相跟随)。

就索引而言,只有两个有任何用途,{ follower: 1, followed: 1 }{ followed: 1, follower: 1 }(两者都只对排序有用,因为这两个中的任何一个都可以涵盖所有过滤情况)。

现在回到设计 2,上面的用例应该是:

鲍勃跟随玛莎

user_followers

[
  {
    user: 'martha',
    follower: 'bob'
  }
]

user_following

[
  {
    user: 'bob',
    following: 'martha'
  }
]

玛莎跟着鲍勃

user_followers

[
  {
    user: 'bob',
    follower: 'martha'
  }
]

user_following

[
  {
    user: 'martha',
    following: 'bob'
  }
]

鲍勃和玛莎互相跟随

user_followers

[
  {
    user: 'bob',
    follower: 'martha'
  }, {
    user: 'martha',
    follower: 'bob'
  }
]

user_following

[
  {
    user: 'martha',
    following: 'bob'
  }, {
    user: 'bob',
    following: 'martha'
  }
]

现在我们可以看到,正如我所指出的那样,设计 2 会复制所有关注者信息,但绝对没有任何好处。

【讨论】:

  • 这不是真的。每个用户可以有任意数量的关注者,并且可以关注任意数量的其他用户。我也可以关注 bob,bob 也可以关注我(例如在 twitter 中)
  • 是的,然后您的单个集合中将有两个条目:一个带有{ followed: 'bob', follower: 'martha' },另一个带有{ followed: 'martha', follower: 'bob' }。但是,对于两个集合,如果 bob 关注 martha,您必须在以下集合中添加一个条目在关注者集合中,基本上注册“bob 正在关注 martha”和“bob 是 martha 的追随者” "(或“martha has bob as follower”),完全一样!
  • @Gorkk:非规范化! :)
  • @SergioTulentsev 它并没有做太多的事情:将(followed: a, follower: b) 存储在一个集合中并将(follower: b, followed: a) 存储在另一个集合中没有任何好处,您只需要在这两个字段中的每一个上都有一个索引。在第一个设计中,总体上存在重复信息,但具有真正的好处:在用户文档中,您有其关注者和关注者;在外部集合中存储关系时,复制该信息没有任何好处。
  • 如何在不牺牲查询性能的情况下结合关注者和关注者数组?
【解决方案2】:

乍一看,我在这里看到设计 1 很可能创建对 mongo 来说太大的文档,并且 16MB 的大小限制可能是一个问题。

另外,您是否考虑过您的索引?我认为如果你必须在一个巨大的数组中搜索一个关系,例如users.following,这对性能来说太糟糕了。我认为像第二种设计那样做更明智。有了它,您就可以拥有性能非常好的简单索引。

PS:followersfollowing 集合真的有原因吗?也许你可以将它们合二为一。

【讨论】:

  • 太棒了!你如何结合以下和追随者?一种方法 - [{user: bob, other_user: mark, type: 1}, {user: bob, other_user: john, type: 2}, {user: bob, other_user: Von, type: 3}] 这里输入 1: bob -> 标记,类型 2:bob 标记(意味着它们彼此跟随)但这似乎使模式和查询复杂化。你如何将两者结合起来?
  • 也许您可以将type 设为一个数组! [{user: bob, other_user: mark, types: [1,2,3]}]
猜你喜欢
  • 2013-03-28
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 2020-06-13
  • 2014-01-20
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多