【问题标题】:Missing Firebase node metadata (one2one chat app)缺少 Firebase 节点元数据(one2one 聊天应用)
【发布时间】:2016-11-16 01:15:05
【问题描述】:

我正在尝试创建“Android 的一对一 Firebase 数据库聊天”。到目前为止,正在使用下面的结构。大字符串代表user_TO_user,KW记录为聊天消息。

chat
  D_57f337e7e55df9ca167d0421_TO_O_57f337e7e55df9ca167d0421
    -KWd06dvkmcoCJd6fNWs
    -KWd7yBoUy-RkEJAlVOB
    -KWd8Au5bPAwMsx3gYhp
    ....
  O_57f337e7e55df9ca167d0421_TO_D_57f337e7e55df9ca167d0421
    -KWd06da-Cx0qjnPUE3l
    -KWd7yBvyLoLd2fiBcia
    -KWd8Au3A_5FJZS8S0qz
    ....

从显示特定用户对话列表的 Android 活动中,我正在创建一个 ListView 并从 Firebase 读取列表:

    String calculated = "O_57f337e7e55df9ca167d0421";    // calculated userId
    firebase_chat.orderByKey().startAt(calculated).endAt(calculated + "\uf8ff").addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String s)        
        {
            // add item to list adapter

        }

}

这很好用。

但我这里有 2 个问题。

首先。我需要使用反向名称制作节点的副本(如上所示,即 A_TO_B 和 B_TO_A),以允许参与聊天的两个用户使用 Firebase 数据库查询功能(因为 substring() 或 contains() 在 Firebase 中不可用过滤器)。有没有更好的查询方法可以防止我复制所有消息?可能有任何节点别名

第二。节点名称本身有助于代码识别喋喋不休的名称......但它对用户演示完全没有帮助。我需要在某处关联用户 O_57f337e7e55df9ca167d0421 是“John Smith”以在屏幕上显示 John Smith。这种机制应该适用于每一个会话节点。

我正在考虑使用每个节点中的第一条记录来存储节点元数据,因此,在获取节点名称后,我可以从 Android 设备查询 DataSnapshot 以查找有关该节点的信息。但是,恐怕这会触发每个对话节点的新后端(Firebase DB)请求以获取其元数据,这可能效率不高,并导致来自每个设备的服务器调用过多。正确的解决方案是将元数据包含在每个节点的名称中...这样我就可以保存第二次调用...。但这在 Firebase 中似乎不可行。

你有什么更有效的方法吗?

谢谢


更新:因此,根据 vzsg 的回答,更好的结构可能是:

  • 消息
    • A_TO_B
      • msg1
      • msg2
      • msg3
    • A_TO_C
      • msg1
      • msg2
      • msg3
    • A_TO_J
      • msg1
      • msg2
      • msg3
  • 聊天
    • 一个
      • A_TO_B
        • B
      • A_TO_C
        • C
      • A_TO_J
        • J
      • A_TO_B
        • 一个
    • C
      • A_TO_C
        • 一个
    • J
      • A_TO_J
        • 一个

这将允许:

  • 在打开对话屏幕时创建一个聊天条目

  • 在第一条消息上创建一个消息条目

  • 查询聊天/A节点以查找A用户的对话,包括其他用户的数据

  • 查询消息/A_TO_B 节点以获取对话的实际消息

(我会稍等片刻接受你的回答,但我喜欢这个提议)


update2:或简化聊天节点:

  • 聊天
    • 一个
      • B
      • C
      • J
      • 一个
    • C
      • 一个
    • J
      • 一个

并动态组合对话名称以获取消息


我在这里描述的最终解决方案:https://github.com/cvivek07/Firebase_Chat/issues/1#issuecomment-260925121

【问题讨论】:

    标签: android firebase firebase-realtime-database


    【解决方案1】:

    首先

    有一种非常简单的方法可以避免重复:在计算组合 ID 时,按字典顺序对两个用户 ID 进行排序。 这样,无论哪个用户在寻找另一个用户,他们都会找到一个对话,而您不必费劲。

    例如:

    • A 到 B 变成 A_to_B
    • B 到 A 变成 A_to_B

    也就是说,这里没有可以提供帮助的查询选项,并且根本不支持别名节点。


    第二

    您有两种选择,各有优劣:

    1. 将参与者用户名复制到聊天节点中,这是您创造的“正确解决方案”。这不一定是真的,但它是可行的:存储很便宜,并且消除额外的查询使客户端代码更简单。但是当用户更改他的名字时,拥有副本会导致问题——所有相关的聊天节点也应该更新。

    2. 将用户节点保存在其他地方,并延迟获取它们以加载用户名(可能还有其他配置文件数据,如图片 URL)。显示列表变得更难实现,但只需要在一个地方进行更新。
      您无需担心“服务器请求过多”,但 SDK 可以轻松处理这些问题。您还可以在内存中缓存已知用户。

    两种解决方案在实践中都有效,您必须决定哪种策略在您的场景中效果更好。


    额外

    呈现的架构中有一个严重的缺陷:当您使用chat 节点来列出对话并在其下列出消息时,客户端必须下载所有内容,包括每条消息没有界限,大量的 CPU 时间和带宽被浪费了。

    您应该考虑将对话列表和消息分开存储;一般来说,目标是扁平的数据库结构。

    【讨论】:

      【解决方案2】:

      添加一些代码以支持 vzsg

      提出的第 1 点
         private String createRoomId(String uid) {
      
          String user1 = uid.substring(10);
          String user2 = FirebaseManager.firebaseUser.getUid().substring(10);
          String roomId;
      
          int result = user1.compareTo(user2);
      
          if (result > 0)
              roomId = user1 + "_" + user2;
          else
              roomId = user2 + "_" + user1;
      
          return roomId;
      }
      

      这最终为聊天室中的参与者创建了一个 UID

      【讨论】:

        猜你喜欢
        • 2017-01-04
        • 2017-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-01
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        相关资源
        最近更新 更多