【问题标题】:Structuring data for chat app in Firebase在 Firebase 中构建聊天应用程序的数据
【发布时间】:2016-09-27 15:16:33
【问题描述】:

我正在关注 structuring data 的 Firebase 指南以获取聊天应用程序。他们提出了如下所示的结构。

{
  // Chats contains only meta info about each conversation
  // stored under the chats's unique ID
  "chats": {
    "one": {
      "title": "Historical Tech Pioneers",
      "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
      "timestamp": 1459361875666
    },
    "two": { ... },
    "three": { ... }
  },

  // Conversation members are easily accessible
  // and stored by chat conversation ID
  "members": {
    // we'll talk about indices like this below
    "one": {
      "ghopper": true,
      "alovelace": true,
      "eclarke": true
    },
    "two": { ... },
    "three": { ... }
  },

  // Messages are separate from data we may want to iterate quickly
  // but still easily paginated and queried, and organized by chat
  // converation ID
  "messages": {
    "one": {
      "m1": {
        "name": "eclarke",
        "message": "The relay seems to be malfunctioning.",
        "timestamp": 1459361875337
      },
      "m2": { ... },
      "m3": { ... }
    },
    "two": { ... },
    "three": { ... }
  }
}

我如何构建我的用户数据,以便我可以轻松地显示他们所属的所有聊天的列表,并为每个聊天显示最后一条消息和时间戳。如果我执行以下结构:

   "users": {
    "ghopper": {
      "name": "Gary Hopper",
      "chats": {
          "one: true",
          "two": true
      }
    },
    "alovelace" { ... }
  },

我可以通过以下方式轻松获取特定用户(例如 ghopper)的每个聊天组的列表:

ref.child("users").child("ghopper").child("chats").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
  //do something with data
}

但是,我不会在此快照中包含 lastMessage 和时间戳。我需要做什么才能访问这些数据?

  • 为每个用户复制所有这些数据?即添加 users/ghopper/chats/one/ {"lastMessage": "ghopper: Relay failure found. Cause: moth.", "timestamp" : 1459361875666}
  • 为用户参与的每个聊天查询“chats/specificGroupId”(添加多个侦听器)?
  • 其他方式?

【问题讨论】:

    标签: swift firebase firebase-realtime-database


    【解决方案1】:

    如何组织我的用户数据,以便我可以轻松地显示列表 他们参与的所有聊天,并且每个聊天都显示 最后一条消息和时间戳。

    通过添加聊天节点中的用户来稍微改变聊天结构

    "chats": {
        "one": {
          "title": "Historical Tech Pioneers",
          "lastMessage": "ghopper: Relay malfunction found. Cause: moth.",
          "timestamp": 1459361875666
          users
           uid_1: true
           uid_3: true
        },
        "two": { ... },
    

    然后您可以深入查询特定用户参与的所有聊天 - 这将返回 uid_3 参与的聊天

    chatsRef.queryOrderedByChild("users/uid_3").queryEqualToValue(true)
         .observeSingleEventOfType(.Value, withBlock: { snapshot in
    
         //.Value can return multiple nodes within the snapshot so iterate over them
         for child in snapshot.children {
              let lastmsg = child.value["lastMessage"] as! String
              let timestamp = child.value["timestamp"] as! String
              print(lastmsg)
              print(timestamp)
         }     
    })
    

    请注意,当通过 auth.uid 创建用户时,每个 firebase 用户都有一个谨慎的用户 ID。这应该(通常)用作每个用户的密钥。

    【讨论】:

    • 您好,Jay,感谢您的回答。我已经尝试过您的解决方案,它似乎可以解决问题。但是考虑到我需要查看所有“聊天/”才能找到用户参与的所有聊天,一旦我有很多用户,这个操作会不会变得太昂贵?
    • @Nilsymbol 很高兴它成功了!看起来您并没有拉下兆字节的数据,只是几百个带有一些子节点的节点。 Firebase 速度非常快,因此在数千个节点上进行这样的查询非常快;它甚至不会让 Firebase 呼吸困难。我们已经测试过了!
    • @Jay 我了解大部分结构,只是不了解用户在“聊天”子项中的表示方式。它是用户 uid 的数组吗?您能否再解释一下布尔值与 uid 的关联?非常感谢! -科尔比
    • @Jay 忽略最后的评论,我现在明白了。一个小小的实验消除了我的困惑。谢谢!
    • @Jay 安全性如何融入其中?如果我的用户不是聊天的一部分并且我将自己添加到该聊天中 - 这意味着我可以查询它 - 这意味着所有用户都可以阅读所有聊天。如果现有聊天成员添加了我 - 那么该聊天成员必须知道我的用户 ID - 这意味着所有用户都可以读取所有用户。有没有解决的办法?如何更新索引?
    【解决方案2】:

    在您拥有用户所在的所有聊天列表的区块中,您可以这样做:

    var dictionary: [String: Long]   
    var lastMessage: String 
    for chat in listOfChatsUserIsIn
        ref.child("chats").child("\(chat)").child("lastMessage").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
            lastMessage = snapshot
            ref.child("chats").child("\(chat)").child("timestamp").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
                //add timestamp and last message to dictionary
            }
        }
    

    我不知道我的语法有多正确。还在学习firebase。但是,我认为这基本上是您的第二个建议。不知道您将如何获取数据。这将是 O(2n) 虽然这还不错。

    [[更新 1]]

    我对我的代码很懒惰。我放了 lastMessage = snapshot 来保存它,这样你就可以在下一个块中将它添加到字典中。

    至于 Firebase 是异步的。我认为只要您使用时间戳或消息作为键,另一个作为字典中的值,这仍然有效。它可能会乱序填充,但您以后总是可以按时间戳对其进行排序。虽然,是的,这可能不是最佳实践。

    Jay,我喜欢你的解决方案。您是否还必须列出uid_2: false

    不幸的是,随着用户 -> inf 和聊天 -> inf,这两个数据库结构似乎都增长了 n^2。

    【讨论】:

    • 由于您没有使用该变量,lastMesssage = snapshot 的功能是什么?此外,在块(闭包)中使用 self.variable 名称是一种很好的做法。此外,第一个 ref.child 中的 ref.child 是重复的,因此它将读取相同的数据。最大的问题是 Firebase 是异步的,并且紧密的 for 循环运行速度会比观察块中返回的数据快 方式,所以我认为我们遇到了一些数据完整性问题 - 可能应该让 Firebase 异步完成它的“东西”。
    • 回答你的答案中的问题.... 不,uid_2: false 不需要,因为它不存在,默认情况下它可能是 false(取决于它的编码)。不,数据库不会成倍增长。如果您有 10 个用户和 1 个聊天,则所有 10 个用户都在该聊天中,因此唯一增长的将是聊天中的用户节点(在我的回答中)同样,如果您有 1000 个用户和 100 个聊天,每个聊天与两个用户,仍然只有 100 个聊天,每个聊天都有一个用户节点和两个用户。即使有 1000 个用户和 1000 个聊天,这也不是大量的数据。
    猜你喜欢
    • 2018-06-01
    • 2016-06-28
    • 2017-06-28
    • 1970-01-01
    • 2018-03-03
    • 2017-11-16
    • 2017-01-04
    • 2019-05-29
    • 2018-02-04
    相关资源
    最近更新 更多