Ios Swift嵌套查询中的Firebase工作不正常

Ios Swift嵌套查询中的Firebase工作不正常,ios,json,swift,firebase,Ios,Json,Swift,Firebase,我有一个JSON结构,如下所示: { "groups" : { "-KAv867tzVgIghmr15CM" : { "author" : "ruben", "name" : "Item A" }, "-KAv87nqLEG1Jtc04Ebn" : { "author" : "ruben", "name" : "Item B" }, "-KAv88yZe8KTfkjAE7In" : { "au

我有一个JSON结构,如下所示:

{
  "groups" : {
    "-KAv867tzVgIghmr15CM" : {
      "author" : "ruben",
      "name" : "Item A"
    },
    "-KAv87nqLEG1Jtc04Ebn" : {
      "author" : "ruben",
      "name" : "Item B"
    },
    "-KAv88yZe8KTfkjAE7In" : {
      "author" : "ruben",
      "name" : "Item C"
    }
  },
  "users" : {
    "rsenov : {
      "avatar" : "guest",
      "email" : "ruben@ruben.com",
      "groups" : {
        "-KAv867tzVgIghmr15CM" : "true",
        "-KAv87nqLEG1Jtc04Ebn" : "true",
        "-KAv88yZe8KTfkjAE7In" : "true"
      }
    }
  }
}
每个用户都有一个带有childByAutoId()键的元素“groups”。然后我有应用程序中存在的所有组的列表

每次运行应用程序时,我都会得到当前用户登录的url引用,并得到该用户的组列表(在本例中,登录的用户是“rsenov”,有3个组)。 对于该用户所属的每个组,我遍历groups url引用,查找这3个组的信息

我是这样做的:

func loadTable() {
    self.groups = []
    var counter = 0
    self.meses = []
    var tempItems = [String]()

    DataService.dataService.CURRENT_USER_GROUPS_REF.observeEventType(.Value, withBlock: { snapshot in

        if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
            tempItems = []
            for snap in snapshots {

                DataService.dataService.GROUPS_REF.childByAppendingPath(snap.key).queryOrderedByChild("name").observeEventType(.Value, withBlock: { snapshot in
                    if let postDictionary = snapshot.value as? Dictionary<String, AnyObject> {
                        tempItems.append(snapshot.value.objectForKey("name") as! String)
                        let key = snapshot.key
                        let group = Group(key: key, dictionary: postDictionary)
                        self.groups.insert(group, atIndex: 0)

                    }
                    counter++
                    if (counter == snapshots.count) {
                        self.meses = tempItems
                        self.miTabla.reloadData()

                    }
                })
            }
        }
    })
}
func加载表(){
self.groups=[]
变量计数器=0
self.meses=[]
var tempItems=[String]()
DataService.DataService.CURRENT_USER_GROUPS_REF.observeEventType(.Value,with block:{snapshot in
如果让快照=snapshot.children.allObjects为?[FDataSnapshot]{
tempItems=[]
用于管理单元快照{
DataService.DataService.GROUPS\u REF.childByAppendingPath(snap.key).queryOrderedByChild(“名称”).ObserveeEventType(.Value,withBlock:{snapshot in
如果让postDictionary=snapshot.value作为字典{
tempItems.append(snapshot.value.objectForKey(“名称”)为!字符串)
让key=snapshot.key
让组=组(键:键,字典:postDictionary)
self.groups.insert(组,索引:0)
}
柜台++
if(计数器==快照.计数){
self.meses=tempItems
self.miTabla.reloadData()
}
})
}
}
})
}
我认为这样迭代不是一个好主意。例如,如果GROUPS\u REF url中的某个子项发生了更改,则该代码仅在该嵌套代码中运行,并且由于它没有从For循环中获取的“snap.key”值,因此它不起作用


在这种情况下,哪种方法是最好的查询方式?

Phew,这需要一些时间来编写。主要是因为我不太喜欢iOS/Swift:

let ref = Firebase(url: "https://stackoverflow.firebaseio.com/35514497")
let CURRENT_USER_GROUPS_REF = ref.childByAppendingPath("users/rsenov/groups")
let GROUPS_REF = ref.childByAppendingPath("groups")

var counter: UInt = 0
var groupNames = [String]()

CURRENT_USER_GROUPS_REF.observeEventType(.Value, withBlock: { groupKeys in
    for groupKey in groupKeys.children {
        print("Loading group \(groupKey.key)")
        GROUPS_REF.childByAppendingPath(groupKey.key).observeSingleEventOfType(.Value, withBlock: { snapshot in
            print(snapshot.value)
            if (snapshot.childSnapshotForPath("name").exists()) {
                groupNames.append(snapshot.value.objectForKey("name") as! String)
            }
            counter++
            if (counter == groupKeys.childrenCount) {
                print(groupNames)
            }
        })
    }
})
顺便说一句,这就是创建一个。代码没有外部依赖项(例如代码中的
Group
DataService
),只包含与答案相关的内容

重要的是:

  • 我使用了
    observeSingleEventOfType
    来获取每个组,因为我不想在组发生更改时获得更多回调
  • 我使用snapshot.childSnapshotForPath(“name”).exists()检查您的组是否有名称。你可能想确保他们都有名字,或者在real app中将他们与其他属性一起添加到列表中

弗兰克的回答切中要害。我想加入一个替代方案,它可能对您的情况有效,也可能对您的情况无效,因为它需要对数据库进行轻微的更改

groups
  gid_0
    author: "ruben"
    name:   "Item A"
    users
      uid_0: true
 gid_1
    author: "ruben"
    name:   "Item B"
    users
      uid_1: true
 gid_2
    author: "ruben"
    name:   "Item C"
    users
      uid_0: true
然后是一些用于深度查询的ObjC代码

Firebase *ref = [self.myRootRef childByAppendingPath:@"groups"];

FQuery *query1 = [ref queryOrderedByChild:@"users/uid_0"];

FQuery *query2 = [query1 queryEqualToValue:@"true"];

[query2 observeSingleEventOfType:FEventTypeValue withBlock:^(FDataSnapshot *snapshot) {
    NSLog(@"key: %@   value: %@", snapshot.key, snapshot.value);
}];
此代码对/users/uid\u 0=true的所有组的/groups进行深度查询。在本例中,它返回gid_0和gid_2

它消除了对迭代和对数据库的多次调用的需要

groups
  gid_0
    author: "ruben"
    name:   "Item A"
    users
      uid_0: true
 gid_1
    author: "ruben"
    name:   "Item B"
    users
      uid_1: true
 gid_2
    author: "ruben"
    name:   "Item C"
    users
      uid_0: true
将/users/node添加到具有uid列表的每个组中可能会提供一些额外的灵活性


只是想一想。

对不起,我已经做好了。不知道该选项是否可用您是对的,组和用户是两个顶级节点,需要澄清;当用户登录时,您希望从他们所属的每个组(组id、作者和姓名)获取数据?感谢您的回答!但是,我遇到了与代码相同的行为。例如,如果组名发生了更改,嵌套代码将不会被调用,即使我将其替换为
observeEventType
也不会工作,因为
groupKey.key
值当时不存在,因为代码没有在for循环中运行。也许,解决方案将使用@JayYup提出的数据库结构,这看起来也不错。无论您选择哪一个,请单击旁边的复选框。因为您是谷歌Firebase的工程师,建议包含一个有助于此类查询的函数不是一个好主意吗?这是一个有趣的评论,我在第一次开始使用NoSQL数据库时也这么认为。SQL来自SQL背景,本质上是一个“行和列的表”,因此您需要构建一个查询以从行/列格式的表中获取数据。NoSQL是一种不同的beast,它没有表,也没有预定义的“结构”(JSON),因此挑战在于如何构造数据以匹配查询。。。。如果要捕获组名何时更改,可以根据注释向/groups节点添加一个观察者。如果您在代码中保留组名,您可能需要考虑创建具有名称和键的组类,并将其保留在数组(或字典)中,并且当名称更改并接收事件时,在密钥的对象数组上使用NSPReDeCATE,并更新密钥的名称或NS字典,并更新名称。如果这不合理(很难在评论中阐述太多),问另一个问题,我们将制定一个解决方案。这是一个好主意!我没想过要用那样的结构。我不确定这是否是构造数据库的最佳方式,但我认为在我的情况下,磁盘空间很便宜,重复数据或双向引用是NoSQL数据库的常见做法,所以不要害怕这样做。有时,您需要在/users节点中引用组,同时还需要在/groups节点中引用用户。