Arrays 通过嵌套的Firebase数据循环填充数组
我想通过从一个firebase节点获取值来填充数组,并使用这些值从不同的firebase节点获取信息。我该怎么做 这就是我的firebase数据库的外观:Arrays 通过嵌套的Firebase数据循环填充数组,arrays,swift,firebase,firebase-realtime-database,Arrays,Swift,Firebase,Firebase Realtime Database,我想通过从一个firebase节点获取值来填充数组,并使用这些值从不同的firebase节点获取信息。我该怎么做 这就是我的firebase数据库的外观: { "MainTree" : { "subTree1" : { "JiRtkpIFLVFNgmNBpMj" : { "PiRterKFLVFNgmFFFtu" : "PiRterKFLVFNgmFFFtu" "TfRterKFLVFNgmFGFre" : "TfRterKFLVFNgmF
{
"MainTree" : {
"subTree1" : {
"JiRtkpIFLVFNgmNBpMj" : {
"PiRterKFLVFNgmFFFtu" : "PiRterKFLVFNgmFFFtu"
"TfRterKFLVFNgmFGFre" : "TfRterKFLVFNgmFGFre",
"X4RterKFLVFNgmaDFca" : "X4RterKFLVFNgmaDFca"
}
},
"subTree2" : {
"PiRterKFLVFNgmFFFtu" : {
"username" : "user1",
"uid" : "PiRterKFLVFNgmFFFtu"
},
"TfRterKFLVFNgmFGFre" : {
"username" : "user2",
"uid" : "TfRterKFLVFNgmFGFre"
},
"X4RterKFLVFNgmaDFca" : {
"username" : "user3",
"uid" : "X4RterKFLVFNgmaDFca"
}
}
}
}
我的职能
func fetchAllInformation(uid: String, completion: @escaping ([UserData]) -> (), withCancel cancel: ((Error) -> ())?) {
let ref = Database.database().reference().child("MainTree").child("subTree1").child(uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
guard let dictionaries = snapshot.value as? [String: Any] else {
completion([])
return
}
var Values = [UserData]()
let group = DispatchGroup()
dictionaries.forEach({ (key, value) in
group.enter()
let ref = Database.database().reference().child("MainTree").child("subTree2").child(key)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userDictionary2 = snapshot.value as? [String: Any] else { return }
let user = UserData(dictionary: userDictionary2)
Values.append(user)
}) { (err) in
print("Failed to fetch all user data from database:", (err))
cancel?(err)
}
})
group.notify(queue: .main) {
print("loop done")
completion(Values)
}
}
}) { (err) in
print("Failed to fetch all data from database:", (err))
cancel?(err)
}
}
我的呼叫功能:
fetchAllInformation(uid: "JiRtkpIFLVFNgmNBpMj", completion: { (userdata) in
print("fetched all userdata! : ",userdata)
}) { (err) in
print("data fetch failed")
}
我的数据结构
struct UserData {
let uid: String
let username: String
init(dictionary: [String: Any]) {
self.uid = dictionary["id"] as? String ?? ""
self.username = dictionary["username"] as? String ?? ""
}
}
这可能是对异步代码的误解。现在的问题是数组变空了。我想你要问的是如何迭代一系列节点,从该节点获取另一个节点的子键,然后基于这些键从另一个节点读取数据 让我从Firebase结构开始,这应该有助于澄清
MainTree
subTree1
some_node
subTree2_0: true
subTree2_1: true
subTree2_2: true
subTree2
subTree2_0:
user_name: "Larry"
subTree2_1:
user_name: "Moe"
subTree2_1:
user_name: "Curly"
这应该与问题的结构相匹配
我们将迭代位于MainTree/subTree1/some_节点中的子节点,以获得我们想要从subTree2读取的节点。我不知道某个_节点相对于其他数据是什么,所以我只是把它叫做。。。某个节点
这段代码的第一部分一次读取subTree1节点的子节点,然后对它们进行迭代以获取每个子键-该子键(例如subTree2_0)对应于subTree2中的子节点
func readMainTree() {
let mainTreeRef = self.ref.child("MainTree")
let subTree1Ref = mainTreeRef.child("subTree1")
let someNodeRef = subTree1Ref.child("some_node")
someNodeRef.observeSingleEvent(of: .value, with: { snapshot in
let childNodes = snapshot.children.allObjects as! [DataSnapshot]
for childSnap in childNodes {
self.readSubTree2At(node: childSnap.key)
}
})
}
在for..循环中,我们获取每个子键,并将其传递给读取子数据(用户名)并打印出来的函数
func readSubTree2At(node: String) {
let mainTreeRef = self.ref.child("MainTree")
let subTree2Ref = mainTreeRef.child("subTree2")
let childRef = subTree2Ref.child(node)
childRef.observeSingleEvent(of: .value, with: { snapshot in
let userName = snapshot.childSnapshot(forPath: "user_name").value as? String ?? "No Name"
print(userName)
})
}
输出为:
Larry
Mo
Curly
如果你愿意的话,你可以加入一个dispatchGroup。。这里有一个使用DispatchGroup的解决方案
func readMainTreeWithDispatch() {
let mainTreeRef = self.ref.child("MainTree")
let subTree1Ref = mainTreeRef.child("subTree1")
let someNodeRef = subTree1Ref.child("some_node")
someNodeRef.observeSingleEvent(of: .value, with: { snapshot in
let childNodes = snapshot.children.allObjects as! [DataSnapshot]
let myGroup = DispatchGroup()
for childSnap in childNodes {
let mainTreeRef = self.ref.child("MainTree")
let subTree2Ref = mainTreeRef.child("subTree2")
let childRef = subTree2Ref.child(childSnap.key)
myGroup.enter()
childRef.observeSingleEvent(of: .value, with: { snapshot in
let userName = snapshot.childSnapshot(forPath: "user_name").value as? String ?? "No Name"
print(userName)
myGroup.leave()
})
}
myGroup.notify(queue: .main) {
print("Finished reading all user names.")
}
})
}
以及输出
Larry
Mo
Curly
Finished reading all user names.
您遇到了什么问题?@bsod firebaser这里的实时数据库与以往一样重要。我们有人积极致力于维护和改进它。虽然Firestore可能更适合某些场景,但实时数据库更适合其他场景。数据是从Firebase异步加载的。任何需要数据的代码都需要在
observe
的结尾处,或者从那里调用。这包括对组的调用。通知(队列:.main){
,它现在在加载数据之前触发,因此当bookmarkedUsers
仍然为空时触发。您可以通过添加一些日志语句来最轻松地进行测试,例如如下所示:@newswitcoder Yes,如果您只输入一次组,您将在调用notify
(据我所知,我绝对不是派遣小组的专家)。但既然你为每件物品打电话enter
,如果我读对了以下答案,你也应该为每件物品打电话leave
:Firebase swag不出售。但是如果你在当地活动中留意Firebase的工作人员,他们通常会带来swag(尽管还没有帽子)。您的工作就在现场!但有一个问题:在所有循环之后,您将如何实现完成侦听器?假设您希望最终结果是数组:[Larry,Mo,Curly]
。我的方法感觉多余,因为它调用完成(值)
每一个循环。谢谢你的回答,杰!我很高兴知道调度组的人能在这里提供帮助。:)@newswiftcoder如果你需要它,我会在早上一起得到一个调度组解决方案。它开始了,我的答案就在后面。@newswiftcoder我用一个调度组的例子更新了答案。如果我的答案有帮助,一定要接受它,这样它可以帮助其他人。@FrankvanPuffelen调度组确实有点奇怪。哈哈。更新了答案与工作代码。