如何在聊天应用程序中构建Firestore数据库结构?

22

存储聊天信息最简单的方式可能是这样:

message:
 -message1 {
   "user1"
   "user2"
   "message"
   "date"
  }
 -message2
 -message3
当应用程序增长到庞大的规模(大量消息),并且在数据库上执行 .whereEqualTo 操作时,以这种方式构造聊天应用程序消息是否存在任何缺点?例如,是否存在使用数据库迭代所有消息的问题?
因为如果使用此方法存在问题,例如,我已经看到了一种结构化数据库的方法,它会将消息分隔在不同的聊天室中。
chats: {
    -chat1 {
      "lastMessage"
      "timestamp"
      "users": {user1, user2}
    }
    -chat2
    -chat3
  }

messages: {
 -chat1 {
  "message"
  "date"
 }
}

但在这个例子中,添加新消息需要用户进行两次写操作:一次是写入新消息,另一次是在客户端更新chat文档的lastMessagetimestamp,或者创建云函数在添加新消息时更新chat文档的值。

那么,第一种选项有效吗?还是应该选择类似第二个例子的方法?


1
如果您感兴趣,也可以查看这个聊天教程。这是Firestore数据库架构 - Alex Mamo
1个回答

45
你提供的第一个选项接近于在关系数据库中建模tblMessages。在NoSQL数据库中,这样的字面转换很少是最佳选择,因为它们具有非常不同的权衡。例如,您已经注意到需要对两个字段执行查询才能获取两个用户之间的消息。
当在NoSQL数据库上建模数据时,我通常建议按照屏幕上所看到的进行建模。因此,如果您的聊天应用程序具有聊天室的概念(即特定人群之间的持久聊天),我也会在您的数据库中对其进行建模。
在Cloud Firestore中,这意味着您将拥有一个顶级集合,其中每个聊天室都有一个文档,然后在每个这样的文档下面有一个该聊天室的消息子集合:
ChatRooms (collection)
  ChatRoom1 (document)
    Messages (collection)
      Message1_1 (document)
      Message1_2 (document)
  ChatRoom2 (document)
    Messages (collection)
      Message2_1 (document)
      Message2_2 (document)

使用这个模型,您不需要查询即可显示聊天室中的消息,而是可以直接从该房间的子集合中加载(所有)消息。它还具有分区房间的优点,这意味着写入可以更好地扩展。
我通常建议将聊天室文档ID建模为参与者,以便您可以根据参与者轻松重构ID。但是还有更多有效的选项。

所以这就像是我的第二个选项,但结合成一个集合,因为如果我想要添加一个监听器来通知用户有新消息在任何一个聊天室中,我仍然需要在“chatRoom”文档中保留类似“lastMessage”的东西,对吧? - Wiktor
1
我通常更喜欢预先计算任何可以的东西,因此每个房间文档中肯定会有一个 lastUpdated 字段。 - Frank van Puffelen
1
你可以在他们的官方文档中找到类似的用例。 https://firebase.google.com/docs/firestore/data-model - Madura Pradeep
我在我链接的问题中的回答展示了如何为每个用户创建一个聊天室列表。 - Frank van Puffelen
@FrankvanPuffelen,您能详细说明为什么建议为每个消息使用一个文档,而不是在表示聊天室的文档中拥有消息数组吗?我是firestore的新手,正在尝试做出架构选择。(还在努力找到确保用户可以发送消息但不能以其他方式更改文档的最佳方法,不确定这是否影响此区别。) - temporary_user_name

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接