2016-02-19 84 views
3

我有一个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" : "[email protected]", 
     "groups" : { 
     "-KAv867tzVgIghmr15CM" : "true", 
     "-KAv87nqLEG1Jtc04Ebn" : "true", 
     "-KAv88yZe8KTfkjAE7In" : "true" 
     } 
    } 
    } 
} 

每个用户都有元素“群”与childByAutoId()键。然后我有应用程序中存在的所有组的列表。

每次运行应用程序时,我都会得到当前用户登录的URL引用,并获取该用户的组列表(在这种情况下,登录用户是具有3个组的“rsenov”) 。 对于这个用户所属的每个组,我遍历组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中的某个子项发生更改,则该代码仅在该嵌套代码中运行,并且由于它没有从for循环获取的“snap.key”值,所以它不起作用。

在这种情况下,哪种方法可以做出好的查询?

+0

对不起,我已经做到了。不知道这个选项是否可用 – Ruben

+0

你是对的,组和用户是两个顶级节点 – Ruben

+0

澄清;当用户登录时,你想从他们所属的每个组中获取数据(group_id,author和name)? – Jay

回答

2

P,需要一些时间写。主要是因为我不知道的iOS /斯威夫特很多:

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。该代码没有外部依赖关系(例如代码中的GroupDataService),并且只包含与答案相关的内容。

重要的位:

  • 我用observeSingleEventOfType获得各组,因为我不想让更多的回调,如果一组更改
  • 我用snapshot.childSnapshotForPath("name").exists()检查,如果你的团队有一个名字。您可能希望确保它们都具有名称,或者将它们添加到列表中,并使用真实应用程序中的其他属性添加它们。
+0

谢谢你的回答弗兰克!不过,我正在经历与我的代码一样的行为。如果组名中有变化,则不会调用嵌套代码,即使我用'observeEventType'代替它也不会工作,因为'groupKey.key'值当时不存在,因为代码不在for循环中运行。可能,解决方案将使用@Jay – Ruben

+0

提出的数据库结构,这看起来也不错。无论您选择哪一个,请点击旁边的复选框。 –

+0

由于您是Google的Firebase工程师,因此建议您提供一个可能有助于此类查询的功能,这不是一个好主意吗? – Ruben

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); 
}]; 

此代码做了深刻的查询上/组为拥有/用户/ uid_0 = true的群体。在这种情况下,它返回gid_0和gid_2

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

使用uid列表向每个组添加a/users /节点可能会提供一些额外的灵活性。

只是一个想法。

+0

这是一个好主意!我没有考虑使用这样的结构。我不确定这是否是构建数据库的最佳方式,但我认为在我的情况下可以很好地工作 – Ruben

+2

磁盘空间便宜,重复数据或双向引用是NoSQL数据库的常见做法,所以不要害怕这样做。有时您需要对/ users节点中组的引用,同时需要在/ groups节点中向用户提供引用。 – Jay