2016-02-19 7 views
3

У меня есть JSON структуры вроде следующего:Firebase в Swift вложенный запрос не работает должным образом

{ 
    "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-адрес пользователя, и я получаю список групп этого пользователя (в этом случае зарегистрированный пользователь «rsenov», который имеет 3 группы) , Для каждой группы, к которой принадлежит этот пользователь, я повторяю ссылку на URL-адреса групп, ища информацию об этих трех группах.

Я делаю это так:

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() 

        } 
       }) 
      } 
     } 
    }) 
} 

Я думаю, что это не очень хорошая идея перебора таким образом. Например, если в URL GROUPS_REF есть изменение какого-либо дочернего элемента, код работает только в этом вложенном коде, и поскольку он не имеет значения «snap.key», полученного из цикла for, он не работает ,

Каков наилучший способ сделать хороший запрос в этом случае?

+0

Извините, я сделал это уже.Не знал, что этот вариант доступен – Ruben

+0

Вы правы, группы и пользователи - это два узла верхнего уровня – Ruben

+0

Чтобы уточнить; когда пользователь входит в систему, вы хотите получить данные из каждой группы, к которой они принадлежат (group_id, author и name)? – Jay

ответ

2

Фу, это заняло некоторое время, чтобы написать. В основном потому, что не 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) 
      } 
     }) 
    } 
}) 

Кстати, это, как вы создаете minimal, complete verifiable example. Код не имеет внешних зависимостей (таких как Group и DataService в вашем коде) и содержит только то, что имеет отношение к ответу.

важные биты:

  • Я использовал observeSingleEventOfType, чтобы получить каждую группу, так как я не хочу, чтобы получить больше обратных вызовов, если группа меняет
  • я использую snapshot.childSnapshotForPath("name").exists(), чтобы проверить, если ваша группа имеет имя , Вероятно, вы захотите либо убедиться, что у всех есть имена, либо добавить их в список с каким-либо другим свойством в реальном приложении.
+0

Спасибо за ваш ответ Фрэнк! Однако я испытываю такое же поведение, как и мой код. Если есть изменения, например, в имени группы, вложенный код не будет вызываться, даже если я заменил его на 'observEventType', это не сработает, потому что значение' groupKey.key' не существует в тот момент, потому что код не работает внутри цикла for. Возможно, решение будет использовать структуру базы данных, предложенную @Jay – Ruben

+0

Yup, что тоже хорошо выглядит. Какой бы вы ни пошли, установите флажок рядом с ним. –

+0

Как вы являетесь инженером Firebase в google, не было бы хорошей идеей сделать предложение о включении функции, которая могла бы помочь для такого рода запросов? – 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 

А потом некоторые Ob кода для Deep Запрос

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 = верно. В этом случае он возвращает gid_0 и gid_2

Это устраняет необходимость повторений и нескольких вызовов в базе данных.

Добавление/users/node в каждую группу со списком uid может предоставить некоторую дополнительную гибкость.

Просто мысль.

+0

Это хорошая идея! Я не думал об использовании такой структуры. Я не уверен, что это самый оптимальный способ структурирования базы данных, но я думаю, что в моем случае это будет хорошо работать. – Ruben

+2

. Дисковое пространство дешево, а дублированные данные или двусторонние ссылки - обычная практика с базами данных NoSQL, поэтому не бойтесь это делать. Бывают случаи, когда вам нужны ссылки на группы в узле/users и в то же время вам нужны ссылки в узле/groups для пользователей. – Jay

 Смежные вопросы

  • Нет связанных вопросов^_^