我想实现用户关注系统。用户可以关注其他用户。我正在考虑两种方法。一个是followers
架构中有followees
和User
,它们都是用户_id
的数组。另一个是模式中只有followers
。每当我想找到用户的关注者时,我都必须搜索所有用户的followers
数组,即db.user.find( { followers: "_id" } );
。这两种方法的优点和缺点是什么?感谢。
答案 0 :(得分:1)
您正在考虑的是这里经典的“多对多”关系。与RDBMS不同,在这种架构中只有一个“正确”的正常形式,在MongoDB中,正确的架构设计取决于您使用数据的方式,以及此处未提及的其他一些因素
请注意,对于这个讨论,我假设“跟随”关系不对称 - 也就是说,A可以跟随B,而B不必遵循A.
1)在MongoDB中有两种基本方法来建模这种关系。
您可以单独收集“以下”文档,如下所示:
{user:ObjectID(“x”),如下:ObjectID(“y”)}
对于以下每种关系,您在此集合中都有一个文档。你需要在这个集合上有两个索引,一个用于“user”,另一个用于“follow”。
请注意,您问题中的第二个建议(在用户文档中包含“跟随”和“跟随”的数组)只是第一个的变体。
2)正确的设计取决于您在此未提及的几个因素。
3)权衡取舍如下:
嵌入式阵列方法的优点是代码更简单,您可以在单个文档中获取整个跟随用户的数组。如果索引“跟随”数组,那么查找所有用户关注者的查询将相对较快,只要该索引完全适合RAM。 (这与关系数据库没有什么不同。)
如果您经常更新关注者,或者您允许无限数量的关注者/关注者,则会出现嵌入式阵列方法的缺点。
如果您允许无限数量的关注者/关注者,那么您可能会溢出MongoDB文档的最大大小。有些人拥有100K以上的粉丝并非闻所未闻。如果是这种情况,那么您将需要采用单独的收集方法。
如果您知道关注者会经常更新,那么您可能也想要使用单独的收集方法。原因是每次添加关注者时,都会增加“关注者”数组的大小。当它达到一定的大小时,它将超过在磁盘上为它保留的空间量,并且MongoDB将不得不移动文档。这将产生额外的写入开销,因为该文档的所有索引也必须更新。
4)如果你想使用嵌入式阵列方法,你可以采取一些措施使其更加可行。
首先,您可以限制一个人可以拥有的关注者总数。其次,当您创建新用户时,您可以创建具有预先创建的大量虚拟关注者的文档。 (例如,您使用大量条目填充'followers'数组,您知道这些条目不会引用任何实际用户 - 也许ID为0.)这样,当您添加新的关注者时,您将替换其中一个ID带有实际条目的0个条目,文档大小不会增长。
其次,您可以限制某人可以拥有的关注者数量,并在应用程序中检查该关注者。
请注意,如果您在文档中使用双数组方法,则会减少一个人可以拥有的最大关注者数量(因为文档的一部分将被他们关注的用户数组占用)。
5)作为优化,您可以更改要跟踪的“跟随”文档。因此,不是每个后续关系都有一个文档,您可以按用户将其删除:
{ user: "X", following: [ "A", "B", "C" ... ] }
{ user: "X", following: [ "H", "I", "J" ... ] }
{ user: "Y", following: [ "A", "X", "K" ... ] }
6)有关多对多模型的更多信息,请参阅此演示文稿:
有关“bucketing”设计模式的更多信息,请参阅MongoDB文档中的此条目:
答案 1 :(得分:0)
如果同时提供followers
和followees
,那么您可以有效地为大多数查询提供服务,而无需在这两个字段中使用二级索引。例如,您可以检索当前用户,然后使用_id上的默认索引来检索所有连接的列表。
db.users.find({_id: {$in: user_A.followers}})
如果您不包含followees
,则需要在followers
上创建辅助索引,以便在没有收集扫描的情况下为某些查询提供服务。例如,要确定用户A的所有跟随者,您将使用如下查询:
db.users.find({followers: user_A._id})
二级索引会花费您一些内存和磁盘空间,但会避免潜在的数据不一致(跟随者和跟随者列表不匹配)。