在Firebase上查询多个键

Gui*_*ura 12 ios firebase swift firebase-realtime-database

我遵循Firebase建议的扁平数据,但是我在列出数据库中的一系列项目时遇到了问题.

这是我的数据库文件的示例:

"users" : {
    "UID12349USER" : {
      "firstName" : "Jon",
      "lastName" : "Snow",
      "email" : "jonsnow@winterfell.com",
      "albums" : {
        "UID124ALBUM" : true,
        "UID125ALBUM" : true
      }
    }
},
"albums" : {
    "UID124ALBUM" : {
      "name" : "My Artwork",
    },
    "UID125ALBUM" : {
      "name" : "My Sketches",
    }
}
Run Code Online (Sandbox Code Playgroud)

我正在检索给定用户的相册列表:

let userAlbums = database.child(usersKey).child(user.uid).child(albumsKey)
userAlbums.observeSingleEventOfType(.Value, withBlock: { snapshot in
    // fetch [UID124ALBUM: 1, UID125ALBUM: 1]
})
Run Code Online (Sandbox Code Playgroud)

现在我希望我可以在一个查询中检索所有用户的相册.我可以做一批查询,并填充异步数组,但这对我来说似乎不是一个好方法......

for key in albumKeys {
    let album = database.child(self.albumsKey).child(key)
    album.observeSingleEventOfType(.Value, withBlock: { snapshot in
        // fetch album.. append to array
    })
}
Run Code Online (Sandbox Code Playgroud)

由于请求的异步性质,使用该方法使得检测查询何时完成变得棘手.除此之外,由于连接错误,某些请求可能会失败.

此外,如果我想过滤一个具有给定名称的专辑(例如"我的艺术作品")或者如果它不存在则返回nil,我最终也会遇到棘手的结束条件.

var found = false

for key in albumKeys {
    let album = database.child(self.albumsKey).child(key)
    album.observeSingleEventOfType(.Value, withBlock: { snapshot in
        // if current.name == "My Artwork"
        // completion(current)
    })
}
// This block will be called before observeSingleEventOfType =.=
if !found {
    completion(nil)
}
Run Code Online (Sandbox Code Playgroud)

我在iOS和Swift上有很好的背景,但我知道Firebase和NoSQL数据库.有人能给我指好方向吗?我应该抛弃Firebase并尝试别的吗?我错过了一些可以查询我需要的方法吗?我的json结构是错误的并且缺少一些额外的键吗?

谢谢

小智 1

我建议使用 aDispatchGroup和互斥来处理 for 循环中的异步函数。以下是您提供的代码,DispatchGroup以确保循环中的所有异步函数在检查 if 语句之前已完成:

let myGroup = DispatchGroup()
var found = false
// iterate through your array
for key in albumKeys {
    let album = database.child(self.albumsKey).child(key)
    // lock the group 
    myGroup.enter()
    album.observeSingleEventOfType(.Value, withBlock: { snapshot in
        if current.name == "My Artwork" {
             found = true
        }
        // after the async work has been completed, unlock the group
        myGroup.leave()
    })
}
// This block will be called after the final myGroup.leave() of the looped async functions complete
myGroup.notify(queue: .main) {
    if !found {
        completion(nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

代码块中包含的任何内容只有在被调用相同次数myGroup.notify(queue: .main) {后才会执行。请务必在 Firebase 观察块内调用(在异步工作之后),并确保即使观察产生错误也能调用它。myGroup.enter()myGroup.leave()myGroup.leave()