如何构建一个生成和跟随系统?
如何构建一个生成和跟随系统?
我在我的社交网络应用中使用Firebase实时数据库,您可以关注并接收您关注的人的帖子。
我的数据库:
Users --USER_ID_1 ----name ----email --USER_ID_2 ----name ----email Posts --POST_ID_1 ----image ----userid ----date --POST_ID_2 ----image ----userid ----date Timeline --User_ID_1 ----POST_ID_2 ------date ----POST_ID_1 ------date
另一个节点“Content”包含所有用户帖子的ID。 如果“A”关注“B”,则将B的所有帖子ID添加到A的时间轴中。 如果B发布了一些内容,它也会添加到所有关注者的时间轴中。
它存在可扩展性问题:
- 如果某人有10,000个关注者,则新帖子将添加到所有10,000个关注者的时间轴中。
- 如果某人有大量帖子,则每个新关注者将在其时间轴中接收到所有这些帖子。
我想改用Firestore,因为它被认为是可扩展的。 我该如何构建我的数据库,以便在Firestore中消除实时数据库中的这些问题?
有两种情况
-
您的应用程序中的用户关注者很少。
-
您的应用程序中的用户拥有大量关注者。如果我们要在单个文档中将所有关注者都存储在单个数组中,则会达到firestore每个文档的1 MiB极限。
-
在第一种情况下,每个用户必须保留一个文档,其中将关注者列表存储在单个文档中的单个数组中。通过使用
arrayUnion()
和arrayRemove()
,可以有效地管理关注者列表。并且当您要在时间轴上发布内容时,必须将关注者列表添加到帖子文档中。并使用下面的查询来获取帖子
postCollectionRef.whereArrayContains("followers", userUid).orderBy("date");
-
在第二种情况下,您只需要基于关注者数组的大小或数量将用户关注文档分解。当数组大小达到固定大小时,下一个关注者ID必须添加到下一个文档中。而第一个文档必须保留字段“hasNext”,其中存储布尔值。
在添加新帖子时,您必须复制帖子文档,每个文档包含早期分解的关注者列表。
并且我们可以使用上面给出的相同查询来获取文档。
我稍晚看到了你的问题,但我也会尽力为你提供我认为的最佳数据库架构。希望你会发现这个答案有用。
我考虑的架构有三个顶级集合: 用户
,用户关注的用户
和帖子
:
Firestore-root | --- users (collection) | | | --- uid (documents) | | | --- name: "User Name" | | | --- email: "email@email.com" | --- following (collection) | | | --- uid (document) | | | --- userFollowing (collection) | | | --- uid (documents) | | | --- uid (documents) | --- posts (collection) | --- uid (documents) | --- userPosts (collection) | --- postId (documents) | | | --- title: "Post Title" | | | --- date: September 03, 2018 at 6:16:58 PM UTC+3 | --- postId (documents) | --- title: "Post Title" | --- date: September 03, 2018 at 6:16:58 PM UTC+3
如果某人有 10,000 个粉丝,那么新帖子将被添加到这 10,000 个粉丝的时间线中。
这将完全没有问题,因为这是 Firestore 中集合的用途。根据建模 Cloud Firestore 数据库的官方文档:
Cloud Firestore 专为存储大量小型文档而进行了优化。
这就是为什么我将 userFollowing
添加为一个集合而不是一个可以包含其他对象的简单对象/映射的原因。请记住,根据有关限制和配额的官方文档,文档的最大大小为 1 MiB(1,048,576 字节)
。对于一个集合,没有关于集合下的文档数的限制。事实上,对于这种结构,Firestore 恰恰进行了优化。
所以以这种方式拥有这些 10,000 个粉丝将完美地运行。此外,您可以以这样一种方式查询数据库,而不需要任何其他的复制。
正如你所看到的,数据库基本上是非规范化的,让你可以非常简单地查询它。在举例之前,让我们创建一个与数据库的连接,并获取使用以下代码行的用户的uid
:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance(); String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
如果您想查询数据库以获取用户正在关注的所有用户,则可以在以下引用上使用get()
调用:
CollectionReference userFollowingRef = rootRef.collection("following/" + uid + "/userFollowing");
因此,您可以获取用户正在关注的所有用户对象。通过其 uid,您可以轻松获取他们的所有帖子。
假设您想在您的时间线上获取每个用户的最新三篇帖子。在使用非常大的数据集时解决此问题的关键是以较小的块加载数据。我已经在我的这个答案中解释了一种推荐的方式,以通过将查询游标与limit()
方法组合对查询进行分页。我还建议您查看这个视频以获得更好的理解。因此,要获取每个用户的最新三篇帖子,您应该考虑使用此解决方案。因此,首先您需要获取您正在关注的前15个用户对象,然后根据他们的uid
,以获取他们的最新三篇帖子。要获取单个用户的最新三篇帖子,请使用以下查询:
Query query = rootRef.collection("posts/" + uid + "/userPosts").orderBy("date", Query.Direction.DESCENDING)).limit(3);
当你向下滚动时,加载其他15个用户对象并获取他们最近的三篇帖子等等。除了日期
,您还可以向帖子
对象添加其他属性,例如喜欢的数量、评论、分享等。
如果有人有大量帖子,那么每个新的关注者都会在他的时间轴中收到所有这些帖子。
不可能。没有必要这样做。我已经解释过为什么。
编辑于2019年5月20日:
优化操作,用户应该查看所有关注的人的最近帖子的另一种解决方案是将用户应查看的帖子存储在该用户的文档中。
因此,如果我们以Facebook为例,您需要有一个包含每个用户Facebook动态的文档。但是,如果单个文档可以容纳太多数据(1 Mib),则需要将该数据放入集合中,如上所述。