【问题标题】:How can I filter a particular set of users stored in the database?如何过滤存储在数据库中的一组特定用户?
【发布时间】:2019-12-11 06:30:47
【问题描述】:

我正在创建一个 iOS 应用程序,其中我的 firebase 实时数据库中有一组标准的用户数据。用户数据由姓名、年龄等值组成。结构如下:

user
 - userId1
  - name : Bob
  - age : 25
 - userId2
  - name : Rob
  - age : 24
 - userId3
  - name : Dylan
  - age : 13

我还有另一个名为“connections”的数据,其结构如下:

connections
 - userId1
   - userId2 : 1
   - userId3 : 1

假设当前用户 ID 是 userId1。现在,当我按下按钮时,我想获取 userId1 的所有连接数据,即 userId2 和 userId3。这里的问题是,如何查看“用户”结构并获取 userId2 和 userId3 的相关用户信息?

简单来说,我如何根据另一个结构中的数据过滤一个结构中的数据?只是似乎无法在线找到正确的解决方案。

我只能获取所有数据。不知道如何过滤数据。

【问题讨论】:

  • 我也抛出了一个答案,但在这种情况下,在 Firebase NoSQL 数据库中,您不是在执行 查询 的意义上“过滤”。您只是在读取特定的数据节点 - /connections/userId1 节点来获取其子节点。读取节点和查询(过滤)数据是非常不同的动物;因此,例如,如果您想要所有 24 岁的用户,那将是一个查询(过滤器)。如果您知道数据的路径,在这种情况下,您正在观察(在这种情况下为 observeSingleEvent)该节点(也就是一次读取该节点)
  • 是的,我明白这一点。我想我应该使用与 sql 相关的“join”这个词。非常感谢您提供的信息。

标签: ios swift firebase firebase-realtime-database


【解决方案1】:

当您刚开始使用 Firebase 时可能会有点棘手,所以这里有一些代码可以与 Kato 的正确答案一起使用。

从概念上讲,首先您想知道此用户连接的 uid。为此,由于我们知道这个用户 uid,我们可以像这样直接从连接节点读取连接数据。

func readConnections() {
    let uid = "userId1"
    let thisUsersConnections = self.ref.child("connections").child(uid)
    thisUsersConnections.observeSingleEvent(of: .value, with: { snapshot in
        let connections = snapshot.children.allObjects as! [DataSnapshot]
        for connection in connections {
            let connectionUid = connection.key
            self.printConnectionInfo(forUserId: connectionUid)
        }
    })
}

填充的快照将包含 userId1 节点的所有子数据,即

   - userId2 : 1
   - userId3 : 1

在这种情况下,我想按照它们在 Firebase 中出现的顺序读取它们,以便我们获取快照中包含的数据并填充一个数组。

let connections = snapshot.children.allObjects as! [DataSnapshot]

注意连接数组中的元素本身就是数据快照。

遍历该数组以获取每个对象(DataSnapshot),每个快照的 .key 是每个用户连接的 uid。然后将密钥传递给另一个函数(为了清楚起见),该函数读取传入的 uid 的用户信息并将名称和年龄打印到控制台。

func printConnectionInfo(forUserId: String) {
    let usersRef = self.ref.child("users").child(forUserId)
    usersRef.observeSingleEvent(of: .value, with: { snapshot in
        let name = snapshot.childSnapshot(forPath: "name").value as! String
        let age = snapshot.childSnapshot(forPath: "age").value as! Int
        print(name, age)
    })
}

【讨论】:

    【解决方案2】:

    首先,您不是在过滤数据,而是在加入数据。所以拥有正确的心态是一个重要的起点。

    假设您没有在每个请求中获取数千个这样的请求(在任何情况下都不应该这样做),答案是这可能无关紧要。 RTDB 使用 websocket 并保持对服务器开放的管道,因此单独请求它们或作为单个查询没有太大区别。它实际上主要是关于字节数,如果您一次获取每条记录或所有记录,它不会改变。因此,只需根据需要获取每个用户。

    在规模上,不要害怕复制少量数据以提高读取效率。如果您只需要用户的名称将它们直接复制到您将执行大规模读取(数十万或更多)的数据中,那很好。

    有一个great series for Firestore 也主要适用于 RTDB,它是 NoSQL 数据结构的重要入门,尤其是第 3 和第 4 集。

    【讨论】:

    • 是的。我明白那个。我想我应该使用与 sql 相关的“join”这个词。感谢您的信息:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-13
    • 2018-12-27
    • 2019-09-21
    • 1970-01-01
    • 2016-07-23
    • 2015-07-29
    • 1970-01-01
    相关资源
    最近更新 更多