4

I have a hierarchical set of data that I want to retrieve information from Firebase. Below is how my data looks:enter image description here

However, my issue is this: Upon looking at how the data is structured, when I want to grab the name or object id of an attendee, I have to perform the following code:

func getAttendees(child: NSString, completion: (result: Bool, name: String?, objectID: String?) -> Void){
    var attendeesReference = self.eventsReference.childByAppendingPath((child as String) + "/attendees")

    attendeesReference.observeEventType(FEventType.ChildAdded, withBlock: { (snapshot) -> Void in

        //Get the name/object ID of the attendee one by one--inefficient?
        let name = snapshot.value.objectForKey("name") as? String
        let objectID = snapshot.value.objectForKey("objectID") as? String
        if snapshot != nil {
            println("Name: \(name) Object ID: \(objectID)")
            completion(result: true, name: name, objectID: objectID)
        }

        }) { (error) -> Void in
            println(error.description)
    }   
}

Now this goes through every attendee child and grabs the name and object id one by one. When the function completes, I store each value into a dictionary. Upon doing so, this function is called multiple times and can be very slow especially when going to/from a database so many times. Is there a more efficient way to do this? I have tried to look into FEeventType.Value but that seems to return everything within the attendees child, when all I really want are the name and objectID of each attendee stored into some sort of dictionary. Any help would be appreciated. Thanks!

Neil Lunn
  • 148,042
  • 36
  • 346
  • 317
user1871869
  • 3,317
  • 13
  • 56
  • 106
  • Answer below, but next time please include the data in a textual format. That way I could've simply modified it, instead of spending time typing data. – Frank van Puffelen Jul 09 '15 at 03:16

1 Answers1

12

One of the golden rules of Firebase is to only nest your data when you always want to retrieve all of it. The reason for this rule is that Firebase always returns a complete node. You cannot partially retrieve some of the data in that node and not other data.

The Firebase guide on structuring data, says this about it:

Because we can nest data up to 32 levels deep, it's tempting to think that this should be the default structure. However, when we fetch data at a location in our database, we also retrieve all of its child nodes. Therefore, in practice, it's best to keep things as flat as possible, just as one would structure SQL tables.

You should really read that entire section of the docs, since it contains some pretty good examples.

In your case, you'll need to modify your data structure to separate the event attendees from the event metadata:

events
  -JFSDFHdsf89498432
    eventCreator: "Stephen"
    eventCreatorId: 1764137
  -JOeDFJHFDSHJ14312
    eventCreator: "puf"
    eventCreatorId: 892312
event_attendees
  -JFSDFHdsf89498432
    -JSAJKAS75478
      name: "Johnny Appleseed"
    -JSAJKAS75412
      name: "use1871869"
  -JOeDFJHFDSHJ14312
    -JaAasdhj1382
      name: "Frank van Puffelen"
    -Jo1asd138921
      name: "use1871869"

This way, you can retrieve the event metadata without retrieving the attendees and vice versa.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Hi, sorry I apologize for the confusion and also the extra typing you had to do. I think I understand what you are saying. However, I just have one related question: when I want to retrieve event attendees information, I have to specify the key of the event. For example, I need to specify `JFSDFHdsf89498432` in the path of my Firebase reference to grab the event attendees. How would I know which is the correct key to specify to grab the correct data? – user1871869 Jul 09 '15 at 04:04
  • For that specific reason I used the same IDs under `events` and `event_attendees`. So to get the event metadata you'd `ref.child('events').child(eventId).on('value'` and to get the attendees for that same event you `ref.child('event_attendees).child(eventId).on('child_added'`. – Frank van Puffelen Jul 09 '15 at 04:07
  • Ah I get you. Thank you very much. Is there any way to track the `eventId` as you suggest in the above comment aside from maybe keeping a separate array and storing in the `eventId` right after creating the event? – user1871869 Jul 09 '15 at 05:25
  • Hi Frank van Puffelen, I have one question. When I call the `FEventType.ChildAdded`, I end up grabbing one child node at at time, if I am I not mistaken. Is there a way to grab every single child node at the same time? For example, in the question above, I want to grab the contents that lie in child `JSAJKAS75478` and `JSAJKAS75412` simultaneously and store that into one big array. I understand that if I do `FEventType.Value` will grab every single attendee at that child node but I also end up getting the reference `JSAJKAS75478` and `JSAJKAS75412` if I'm not mistaken. – user1871869 Jul 10 '15 at 22:51
  • 1
    @FrankvanPuffelen Hello. I have recently asked a question but unfortunately didn't receive a satisfactory response. As I can see, you also included the name of the event attendees. Is this a good practice? What if a user decides to change his/her name? This means that you will have to update all the event_attendees children of that user. Thanks. – Toma Radu-Petrescu Feb 22 '18 at 17:53