我查看了几篇 StackOverflow 帖子,了解如何通过对几个节点深的子值进行相等来获取数据值。
在 Firebase 数据库中 - 如何执行前缀通配符查询 数据库结构为:
并且查询
ref.child("user_id").orderByChild("name").equalTo("objective-c")
可以提取具有特定uid的子项。
在Firebase按子值搜索中,数据库结构为:
并且查询
ref.child('users').orderByChild('name').equalTo('John Doe')
能够找出合适的孩子。
在这两种情况下,排序和相等都是由孙子完成的。然而,就我而言,数据库结构有点不同。我想按几层深的子属性进行索引。其结构为:
所以我尝试运行以下查询:
authenticatedUsersReference.queryOrdered(byChild: fcmTokenKey).queryEqual(toValue: fcmToken).observeSingleEvent(of: .value)
,我的快照返回nil
。但是当我运行 authenticatedUsersReference.queryOrdered(byChild: fcmTokenKey).observe(.value)
时,我看到快照值是按 fcmToken 排序的。 authenticatedUsersReference
指向Database.database().reference().child("people/authenticated")
。我还更新了我的规则以在服务器端建立索引。据我所知,即使深度发生变化,这个概念也应该保持不变,那么我错过了什么导致我的查询返回nil
?
"people": {
"users": {
"authenticated": {
"$userName": {
".indexOn": ["fcmToken"]
}
}
}
}
您正在
$userName
上为 fcmToken
定义索引。这允许您查询特定 $userName
节点的 fcmToken
属性。
但是您的代码会查询所有用户的
fcmToken
属性,而该属性不存在索引。因此,第一个修复是您需要在要查询的位置上定义索引,依此类推 authenticated
:
"people": {
"users": {
"authenticated": {
".indexOn": ["fcmToken"]
}
}
}
现在上面在正确的位置创建了索引,所以让我们看看它在索引中放入了什么值。
对于
authenticated
的每个子节点,上面获取其 fcmToken
属性并将该属性的值放入索引中。但是如果我们查看您的 JSON,authenticated
的子节点没有 direct 子属性 fcmToken
。因此,索引中没有任何值可放入,这解释了为什么您没有得到查询结果。
相反,您在(固定)路径有一个子属性:
stats/fcmToken
,所以这也是您应该在索引定义中使用的。
总共:
"people": {
"users": {
"authenticated": {
".indexOn": ["stats/fcmToken"]
}
}
}
根据该定义,索引中存在正确的值,您可以使用以下方式查询它:
authenticatedUsersReference
.queryOrdered(byChild: "stats/fcmToken")
.queryEqual(toValue: fcmToken)
一旦获得此快照,所有与获取密钥相关的方法都将不再有用,因为根引用是
authenticated/
。所以snapshot.ref
,snapshot.key
都会指向这一点。
大多数此类问题都需要能够获取与检索到的子项关联的 UID。 (例如,如果多个用户的 firToken 相同,则可以是多个)
实现此目的的最小方法,无需使用
JSONDecoder
进行复杂且不必要的解析,如下所示:
{(snapshot) in
guard let value = snapshot.value as? [String: Any] { return }
let uids = Array(snapshot.keys)
print("UIDs for with matching FCMToken are: \(uids)")
//UIDs for with matching FCMToken are: ["userId", "otherUserId"]
}