在 Firebase DatabaseReference 上调用 getData 会返回父引用的数据

问题描述 投票:0回答:2

问题

使用 Firebase iOS SDK,我尝试从数据库中顶级节点的子节点获取数据,但从中获取数据会为我提供整个顶级节点的数据。

我的数据库中有一个顶级节点。我正在尝试从该节点的直接子节点获取数据。所以,当我在这一行放置断点时:

databaseRef.getData { error, snapshot in

并将

databaseRef
打印到控制台,它会显示子级的 URL。但是,如果我在该闭包内部放置一个断点,并将快照打印到控制台,它将显示父级的数据。我将 Firebase 控制台并排放置,因此我可以清楚地看到它。 我尝试过的事情

在你可以问之前,不,这不是不同实例的回调,因为我什至尝试在闭包中保留对

databaseRef

的引用并在那里再次打印出来。方法如下:

func getOnce() -> Future<T?, ReceiveError> {
    let promise = Promise<T?, ReceiveError>()

    let decoder = decoder
    let ref = databaseRef // databaseRef is a property on this object
    databaseRef.getData { error, snapshot in
        print(ref)
        // => https://[REDACTED]-default-rtdb.firebaseio.com/invite_codes/jake-email_com for example
        print(snapshot)
        // => The content of https://[REDACTED]-default-rtdb.firebaseio.com/invite_codes
        let result = result(
            forError: error,
            snapshot: snapshot,
            usingDecoder: decoder
        )
        promise.complete(withResult: result)
    }
        
    return promise.future
}

ref

最终如预期的那样:它显示了子级的 url,而

snapshot
显示了父级的数据。
如何获取我的数据库参考

我有父级的现有数据库参考。它的行为完全符合预期,出售与底层 URL 匹配的数据。其底层 URL 如下所示:

https://[REDACTED]-default-rtdb.firebaseio.com/invite_codes

子项的数据库引用是通过获取用户的电子邮件地址并将 

@

替换为

-
以及将
.
替换为
_
来创建的。因此,如果我输入
[email protected]
,代码将调用:
parentReference.child(encodedEmail)

其中 
encodedEmail

"jake-some_email"
当该引用打印到控制台时,其 url 与预期一致,采用以下形式:

https://[REDACTED]-default-rtdb.firebaseio.com/invite_codes/jake-some_email

但是,当我对其调用 

getData(completion:

时,我会获取父引用的数据,其中

包含
URL 将表示的节点,因为快照最终看起来像这样: Snap (jake-some_email) { "jake-someemail_com" = { // the data that I want }; "another-email_com" = {

等等等等

注意上面的引用是 TO

jake-some_email

但它也包含

jake-someemail_com
。从 Firebase 控制台查看数据库显示没有与之匹配的结构。
    

ios swift firebase firebase-realtime-database
2个回答
0
投票
https://github.com/firebase/firebase-ios-sdk/issues/12965

目前,我的解决方法是将单个事件侦听器转换为异步函数。

extension DatabaseReference { func toAsyncSnapshot() async -> DataSnapshot { return await withCheckedContinuation { continuation in self.observeSingleEvent(of: .value) { snapshot in continuation.resume(returning: snapshot) } } } }

这是将回调转换为异步代码时的典型模式;很多语言都实现了它。

这里的延续是某种

deferred

块,它会一直阻塞,直到延续变成

resume
如果您需要更多上下文,可以搜索 

sempahore

或“倒计时锁存器”(这是 Java 特有的)。

如果您对我的解决方法有任何想法,请告诉我,有时我倾向于忽略 Swift 上的重要事情,干杯。


-1
投票

代码:

FirebaseApp.configure() let data = [ "child" : true, "otherChild": true] let root = Database.database().reference() let parentRef = root.child("parent") let childRef = parentRef.child("child") parentRef.setValue(data) childRef.getData { err, snap in if err != nil { print("Error: \(err!)") } if (snap != nil && snap!.exists()) { print(childRef) print(snap!) } } childRef.observeSingleEvent(of:.value, with: { snap in print("Snapshot from once: \(snap)") }) parentRef.getData { err, snap in if err != nil { print("Error: \(err!)") } if (snap != nil && snap!.exists()) { print(parentRef) print(snap!) } }

这样数据库中的数据就变成了:

tree with a parent node with two child nodes as written by the code above 输出:

https://fir-multi-shards.firebaseio.com/parent/child Snap (child) 1 Snapshot from once: Snap (child) 1 https://fir-multi-shards.firebaseio.com/parent Snap (parent) { child = 1; otherChild = 1; }

正如您所看到的,写入的路径和值与我们在代码中的两个引用相匹配。

© www.soinside.com 2019 - 2024. All rights reserved.