我有一个如下的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"
}
}
}
}
每个用户都有元素" groups"使用childByAutoId()键。然后我有应用程序中存在的所有组的列表。
每次运行应用程序时,我都会获得当前用户记录的url引用,并获得该用户组的列表(在这种情况下,登录用户是" rsenov"那有3组)。 对于该用户所属的每个组,我遍历组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()
}
})
}
}
})
}
我认为以这种方式迭代不是一个好主意。例如,如果GROUPS_REF url中的某个子项发生了更改,则代码只会在该嵌套代码中运行,并且因为它没有&#34; snap.key&#34;从for循环得到的值,它不起作用。
在这种情况下,哪种方法可以做出更好的查询?
答案 0 :(得分:2)
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)
}
})
}
})
顺便说一句,这就是你创建minimal, complete verifiable example的方法。代码没有外部依赖项(例如代码中的Group
和DataService
),只包含与答案相关的内容。
重点:
observeSingleEventOfType
来获取每个组,因为如果组更改,我不想获得更多回调snapshot.childSnapshotForPath("name").exists()
检查您的论坛是否有名称。您可能希望确保它们都具有名称,或者将它们添加到列表中,并在真实应用程序中添加其他属性。答案 1 :(得分: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
然后是深度查询的一些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_0 = true的所有组的/ groups进行深层查询。在这种情况下,它返回gid_0和gid_2
它消除了迭代和多次调用数据库的需要。
使用/ uid列表向每个组添加/ users /节点可以提供一些额外的灵活性。
只是一个想法。