哪个是用于获取社交媒体提要的最佳 Firestore 架构?

Dan*_*ein 5 firebase google-cloud-firestore

我正在考虑将 Firestore 用于社交媒体提要的几个想法。到目前为止,我的想法还没有实现,所以对于这个想法,我希望得到社区的反馈。

这个想法是允许用户发布信息,或记录他们的活动,并向任何关注/订阅该信息的用户显示它。帖子信息将位于名为posts.

据我所知,这些方法需要的读取和写入次数大致相同。

一个想法是在users/{userId}有一个名为 posts 的字段中,它是一个我有兴趣为用户提取的 documentIds 数组。这将允许我直接从数据中提取posts并获取最新版本的数据。

另一种方法似乎更像是 Firebasey,它是将文档存储在 users/{userId}/feeds 中,这些文档是帖子本身的副本。我可以使用相同postID的数据posts。据推测,如果我需要为任何评论更新数据,我可以使用组集合查询来获取所有称为提要的集合,其中 docID 是相等的(或者只是创建一个字段来执行适当的操作"where", "==", docId)。

第三种方法是更新应该查看帖子的人员列表。只要帖子列表比关注者列表短,这似乎更好。您不是在每个关注者上维护所有帖子,而是在每个帖子上维护所有关注者。对于每个新关注者,您都需要更新所有帖子。

此列表不会是用户自己的帖子。相反,它将是显示该用户的所有帖子的列表。

三个挑战者:

  1. users/{userId} 与字段称为feed- 指向全局帖子的文档 ID 数组。获取该提要,通过 ID 获取所有文档。每次用户有活动时,都需要为每个关注者更新每个数组。

    users (coll)
        -> uid (doc)
        -> uid.feed: postId1, postId2, postId3, ...] (field)
    
    posts (coll)
        -> postId (doc)
    
    Run Code Online (Sandbox Code Playgroud)

查询(伪):

doc(users/{uid}).get(doc)
    feed = doc.feed
    for postId in feed:
        doc(posts/{postId}).get(doc)
Run Code Online (Sandbox Code Playgroud)
  1. users/{userId}/feed 其中包含posts您希望该用户看到的所有内容的副本。每个活动/帖子都需要添加到每个相关的提要列表中。

    users (coll)
        -> uid (doc)
             -> feed: (coll)
                   -> postId1 (doc)
                   -> postId2
                   -> postId3
    
    posts (coll)
        -> postId (doc)
    
    Run Code Online (Sandbox Code Playgroud)

查询(伪):

collection(users/{uid}/feed).get(docs)
    for post in docs:
        doc(posts/{post}).get(doc)
Run Code Online (Sandbox Code Playgroud)
  1. users/{userId}/feed 其中包含posts您希望该用户看到的所有内容的副本。每个活动/帖子都需要添加到每个相关的提要列表中。

    users (coll)
        -> uid (doc)
    
    
    posts (coll)
        -> postId (doc)
        -> postId.followers_array[followerId, followerId2, ...] (field)
    
    Run Code Online (Sandbox Code Playgroud)

查询(伪):

collection(posts).where(followers, 'array_contains', uid).get(docs)
Run Code Online (Sandbox Code Playgroud)

读/写

1. 更新数据 对于user每项活动的作者,查找关注该用户的所有用户。目前,用户作为文档存储在集合中,因此这是 followerNumber 文档读取。对于每个用户,通过预先添加postId这将是 followerNumber 文档写入来更新他们的数组。

1. 显示数据/提要 对于提要的每次获取:从用户文档中获取数组(读取 1 个文档)。对于每个 postId,调用,posts/{postId}

这将是 numberOfPostsCalled 文档读取。

2. 更新数据 对于user每项活动的作者,查找关注该用户的所有用户。目前,用户作为文档存储在集合中,因此这是 followerNumber 文档读取。对于每一个用户来说,用ID添加新文档postIdusers/{userId}/feed这将是followerNumber文件写入。

2. 显示数据/提要 对于提要的每次获取:从以下位置获取一定数量的帖子users/{userId}/feed

这将是 numberOfPostsCalled 文档读取。

第二种方法要求我在编辑时使所有文档保持最新。因此,尽管这种方法看起来更像 firebase,但postId直接持有 a和 fetch的方法似乎更合乎逻辑。

3. 更新数据 对于每个新关注者,被关注者发表的每篇帖子都需要更新。新的追随者被附加到一个名为追随者的数组中。

3. 显示 每次获取提要的数据:从posts哪里获取一定数量的帖子uid == viewerUid

and*_*res 1

很好,当我谈论什么是更优化时,我确实需要一个点或质量属性来比较,我会假设您关心速度(不是必需的性能)和成本。

这就是我解决问题的方法,它涉及多个集合,但我的目标只是 1 个查询。

用户(列)

{
 "abc": {},
 "qwe": {}
}
Run Code Online (Sandbox Code Playgroud)

帖子(列)

{
  "123": {},
  "456": {}
}
Run Code Online (Sandbox Code Playgroud)

用户帖子(列)

{
  "abc": {
    "posts_ids": ["123"]
  }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切顺利,问题是,我需要进行多次查询才能获取所有帖子信息......这就是云函数发挥作用的地方。您可以创建第四个集合,您可以在其中预先计算您的 Feed

用户仪表板

{
  "abc": {
    posts: [
    {
       id: "123", /.../
    }, {
       id: "456", /.../
     }
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

云函数看起来像这样:

/* on your front end you can manage the add or delete ids from user posts */
export const calculateDashboard = functions.firestore.document(`users_posts/{doc}).onWrite(async(change, _context) {
   const firestore = admin.firestore()
   const dashboardRef = firestore.collection(`users_dashboard`)
   const postRef = firestore.collection(`posts`)

   const user = change.after.data()
   const payload = []
   for (const postId of user.posts_ids) {
      const data = await postRef.doc(postId).get().then((doc) => doc.exists ? doc.data() : null)
      payload.push(data)
   }
   // Maybe you want to exponse only certain props... you can do that here
   return dashboardRef.doc(user.id).set(payload) 
})
Run Code Online (Sandbox Code Playgroud)

文档最大大小是1 MiB (1,048,576 bytes)您可以存储的大量数据,因此您可以在这里发布很多帖子。我们来谈谈成本;我曾经认为 firestore 更像是有几个小文档,但我发现在实践中它同样可以很好地处理大尺寸的大量文档。

现在在你的仪表板上你只需要查询:

const dashboard = firestore.collection(`users_dashboard`).doc(userID).get()
Run Code Online (Sandbox Code Playgroud)

这是解决这个问题的一种非常固执己见的方法。您可以避免使用users_posts,但也许您不想为与帖子相关的更改以外的其他内容触发此过程。