【问题标题】:Firebase realtime database structure in chat app聊天应用程序中的 Firebase 实时数据库结构
【发布时间】:2017-11-16 01:52:26
【问题描述】:

对不起,我的英语水平不好,我来自阿根廷。

我在 Firebase 中有以下消息数据结构:

"messages"
   "-KezmqXSdKCNFFA432Uc___-KfCEwklG_y3naRDIUiY"
         "messageDate": "20170620"
         "messageTime": "18:44" 
         "message": "Hi"
   "-KezFDSAADFASFFS3221___-KASDF32324SDFASD1FS"
         "messageDate": "20170620"
         "messageTime": "22:23" 
         "message": "How are you?"

其中-KezmqXSdKCNFFA432Uc-KfCEwklG_y3naRDIuiY-KezFDSAADFASFFS3221-KASDF32324SDFASD1FS是用户。

我的问题是我在“消息”节点中创建了一个 childEventListener 来接收新用户消息,但我正在接收所有用户的所有新消息(我每个应用程序登录一个用户),因为我的 childListener 位于“消息”节点。

如果我在添加消息时有 1000 个用户,那么新消息会到达 1000 个用户,这是否正确? (假设在应用内,您可以检查该消息属于哪个用户)。

谢谢!

【问题讨论】:

  • 您有聊天室还是只有一个聊天室可供这 1000 个用户使用?
  • 这不是聊天室。这是一个类似whatsapp的应用程序。问题是“消息”节点中的子监听器。这个节点拥有所有用户的所有消息,那么如果一个用户向另一个用户发送消息,它就会到达所有用户。

标签: android firebase firebase-realtime-database structure


【解决方案1】:

如果你做一个类似这样的结构:

-chats
   - chatUID
       - members
           - userUID
       - lastMessageSent:messageUID
       - ... more properties  

-chatMessages
   - chatUID
     - messageUID
         - sentBy: userUID
         - messageDate:""
         - messageTime:""
         - message:""

-userChats
    - userUID
       - chatUID

您可以将侦听器附加到 /userChats/userUID,这将显示活动聊天,并将侦听器附加到 /chatMessages/chatUID,它将获取特定聊天对话的所有聊天消息。

这种方式更容易设置 Firebase 安全规则,用户只会收到与他们不同的聊天消息。

【讨论】:

  • 我明白了。无论如何,我需要从 firebase 实现函数和触发器,对吧?
  • @Linxy userA 和 userB 在聊天室中,并且都为/chatMessages/chatUID 添加了监听器。现在如果 userA 在chatUid 中推送一条新消息,那么用户 A&B 都会通过他们的听众收到这条新消息?这对用户A来说是不是浪费带宽,因为他自己推了它。是否可以有一个 Db 结构,以便 userA 只收听来自 userB 的消息?
  • 在这种情况下,您将如何计算未红色消息?这个问题很老,使用实时数据库而不是我使用的 firestore,但我对集合有同样的看法。我也问了question
  • 另外,这将需要每个 charUid 的侦听器。在用户通常有 1k 个聊天室的情况下,维护所有这些侦听器可能会占用大量内存。
【解决方案2】:

感谢@Linxy 的精彩回答

我已经创建了一个关于 @Linxy 答案的 firebase 数据库

这是完整的 JSON 导出

{
  "Chats" : {
    "-Lsfsd234xda" : {
      "lastMessageSent" : "-LrDEBo1-Message",
      "members" : [ "-LrDEBoLokW-5mhaT3ys", "-LrDEBoLokW-5mhaT3yz" ],
      "more_properties" : "goes here"
    }
  },
  "Users" : {
    "-LrDEBoLokW-5mhaT3ys" : {
      "id" : "-LrDEBoLokW-5mhaT3ys",
      "userDisplayName" : "Qadir Hussain",
      "userEmail" : "XXXXX.XXXX@gmail.com",
      "userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7XXXXXXXXX"
    },
    "-LrDEBoLokW-5mhaT3yz" : {
      "id" : "-LrDEBoLokW-5mhaT3ys",
      "userDisplayName" : "Ishaq Bhojani",
      "userEmail" : "XXXXXXX.XXXXXX@gmail.com",
      "userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7mB3KTbXXXXXXXX"
    }
  },
  "chatMessages" : {
    "-Lsfsd234xda" : {
      "-LrDEBo-MessageUID" : {
        "message" : "Hi there!",
        "messageDate" : "10/10/2019",
        "messageTime" : "10:16pm",
        "sentBy" : "-LrDEBoLokW-5mhaT3ys"
      },
      "-LrDEBo1-MessageUID" : {
        "message" : "Hello",
        "messageDate" : "10/10/2019",
        "messageTime" : "10:17pm",
        "sentBy" : "-LrDEBoLokW-5mhaT3yz"
      }
    }
  },
  "userChats" : {
    "-LrDEBoLokW-5mhaT3ys" : {
      "0" : "-Lsfsd234xda",
      "1" : "-Lsfsd234xda1",
      "chatUID" : "-Lsfsd234xda"
    }
  }
}

【讨论】:

  • 你能分享一下你用来设置这个结构的代码吗?
  • 不知道chatUID,只知道发送者的userUID,如何查询消息的接收者?
【解决方案3】:

我知道现在回答已经晚了,但对于未来的读者来说,虽然 Linxy 的回答更简洁,但我想指出一个更有效的一个,已经尝试了两种结构:

ChatMessages
   smallerUID_biggerUID
      messageUID
         sentBy : userUID
         messageDate : ""
         message : ""
      .
      .
   .
   .
UserChats
   userUID
      pairUID
        lastMessage : ""       
      .
      .
   .
   .

通过这种方式,我们可以直接搜索哪些用户应该出现在我们的活动聊天选项卡中并获取用户信息(用户名、个人资料图片),而不是先找出聊天 ID,然后再找出与该聊天 ID 关联的用户。这样做的原因是,如果我们知道我们想与之发送消息的用户 ID,我们总是可以计算 chatId。所以对于消息标签,我们在客户端计算chatId(smallerUID_biggerUID)并搜索引用它的消息。

【讨论】:

  • 您能否再解释一下您的推理,我对您如何计算客户端的 uid 感到困惑。你不是必须遍历所有用户并混合搭配吗?
  • 不太确定我是否有不清楚的地方,所以让我举个例子来解释一下。假设我们有一个活动显示活跃的聊天用户(客户端至少有 1 条消息的用户)。为了显示这一点,我们在 UserChats/userUID(客户端的 id)下获取数据。然后当客户端点击其中一个用户时,我们需要显示客户端和被点击用户之间的消息。每个消息对都被唯一标识为“smallerUID_biggerUID”。我们已经获得了希望查看客户端消息的 uid,并且我们知道自己的 id。所以我们可以计算这对的chatId并得到他们的mssgs
  • UID 越来越小对我来说是有意义的,但是使用这个系统,您是否仍然需要查询所有其他用户的 UID 才能计算所有其他聊天节点 id跨度>
  • 您可以通过在 UserChats/userUID 上附加一个监听器来计算我们之前聊天的人的聊天 ID。但我想我明白了你现在要问的。要获取所有 userUID,您可以使用您喜欢的任何类型的查询简单地从用户那里获取所有 userUID 并显示它们。只有当您单击其中一个用户时,您才需要计算 chatid 并将侦听器附加到 chatMessages。所以我想说的是你不需要获取或计算所有的聊天 ID。 recyclerview 元素应该只包含pairInfo(pairUsername、pairUID等),而不是chatId。
【解决方案4】:

为了构建您的数据库,请阅读这篇文章:Structuring your Firebase Data correctly for a Complex App。您一定会在这里找到问题的答案。

作为结论,请尝试尽可能地扁平化(非规范化)您的数据库。

希望对你有帮助。

【讨论】:

    【解决方案5】:

    这个结构不支持你想做的事情,最好通过使用类似频道的东西来改变它,其中一个频道包含两个人之间的消息,所以当他们中的任何一个发送消息时,另一个将是通知。

    【讨论】:

    • 我明白,但是我应该为两个用户之间的每个对话创建频道,并让这些用户通过儿童听众收听该频道?在这种情况下,是否应该创建动态通道和动态子事件?
    • 一旦其中一个向另一个发送消息并将其添加到两个用户的频道列表中,就会创建频道,您可以使用firebase函数在数据库上添加触发器以发送推送通知或添加频道节点上的监听器并测试用户是否拥有该频道,或在指定节点上添加事件监听器
    • 在这种情况下,用户应该连接到尽可能多的儿童听众,因为他们有对话。这是正确的方法吗?
    • 不幸的是,这就是为什么您需要使用 firebase 功能,这样您就不需要本地通知并获得推送
    • 所以我阅读了有关 firebase 函数的信息,我应该从用户“A”在 firebase 中创建一个新频道,然后创建一个函数来向用户“B”表明他已收到一条消息并且他必须将侦听器连接到通道。但是那个函数,应该是从android创建的吧?
    【解决方案6】:
    {
        "users": {
            "userId": {
                "conversations": {
                    "conversationId": {
                        "unseenCount": 0
                    },
                    "conversationId2": {
                        "unseenCount": 3
                    }
            }
        },
        "conversations": {
            "conversationId": {
                "displayedMessage": "Message",
                "members": {
                    "userId1": true,
                    "userId2": true
                },
                "messages": {
                    "messageId": {
                        "type": "text",
                        "text": "Hello",
                        "createdAt": "",
                        "senderId": "userId",
                        "status": "sent",
                        "payload": ""
                    }
                },
                "lastMessage": "my last message"
            }
    }
    

    }

    【讨论】:

    • 虽然可用,但非常愚蠢。如果我有 5000 个对话,每次您登录或用户更新时,您都会加载所有 5000 个对话 ID :)
    【解决方案7】:

    我认为这将是它的最佳结构:

    {
      messages: {
        A8Fcn28ak9ask46: {
          chat_id: "combination of sender and receivers number",
          sender_id: "person sending the message", 
          receiver_id: "person send it to",
          text: "message that the user types",
          timestamp: "123981849404"
        },
        ...
      }
     }
    

    然后当你得到结果时,你可以通过chat_id的正向和反向过滤,这将得到两个人之间的对话。

    希望对你有帮助。

    【讨论】:

    • 这是最低效的解决方案。您正在让所有用户获取系统中的所有数据。您的应用永远不会扩展。
    猜你喜欢
    • 2018-06-01
    • 2018-03-03
    • 2017-01-04
    • 1970-01-01
    • 2020-06-13
    • 2023-04-04
    • 2016-09-27
    • 2016-06-28
    • 2019-02-23
    相关资源
    最近更新 更多