1

From the articles I've read about keeping "references" in Firebase (1, 2, 3), I've failed to understand which would be the best way to reference other objects, if we need to listen to all the referenced object's attributes.

Data:

I have users, that can get into the role of a player, when they join a tournament:

"t_3515":{  
   "entry_fee":100,
   "status":"Cancelled",
   "players":{  
      "p_3":{  
         "player_name":"User A",
         "score":"0",
         "status":"Waiting"
      },
      "p_4":{  
         "player_name":"User B",
         "score":"0",
         "status":"Accepted"
      }
   }
}

I have a list with all the system's tournaments.

How I have to show this data:

  • One screen that shows/listens "all" the list of tournaments.
  • One screen with shows/listens the tournaments that the logged user belongs to.

I'm looking for the best way (in terms of performance) to structure the data for both requirements.


Possible solution 1:

Duplicate each tournament for each player, which means:

  • accessing an user's tournaments with firebaseURL//tournaments, making it easy for a client to display it in a list. (good!)
  • each whole tournament will be copied in each player's URL. (bad?)

Possible solution 2:

Follow this approach, which means:

  • to access the user's tournaments, client should subscribe to firebaseURL//tournaments (to know when a tournament is added/removed), then iterate over each tournament, look for its original data's URL, and subscribe to it. (horrible)
  • The tournament's data will be kept in one place only. (good)

Theoretically, this app will have thousands of tournaments and users, which I guess is something to keep in mind if we end up duplicating the data like in solution 1.

RominaV
  • 3,335
  • 1
  • 29
  • 59
  • Why do you want to keep references? If you are observing a node it will tell you if there are any changes. For example; User_A is logged in and looking at the All Tournaments screen (the tournaments node is being observed). A new tournament is started by User_B. User_A will be automagically notified of that event so you can update their to show it. If User_A then switches to the My Tournaments screen, that's a simple filter in code to only show tournaments they are part of. The challenge is structuring the Firebase data. Can you update your question with what you want to do with references? – Jay May 17 '16 at 17:08
  • @Jay , "switching to My Tournaments screen, that's a **simple filter in code** to only show tournaments they are part of". I'm currently observing the url with all the tournaments, and when switching to "My Tournaments", I loop over them to get the ones the user's part of, but it's getting super slow on both iOS and Android because there are hundreds of tournaments. Are you suggesting doing it with Firebase Query? I need to update "My Tournaments" in real time, that's why I need to subscribe to each user's tournament. – RominaV May 17 '16 at 17:28
  • While technically you could do this with Firebase, that's a lot of extra work and looping is terribly inefficient. Use an NSPredicate to filter, and the result is an array of the tournaments you want, then use that array to update your tableView. NS predicate would filter thousands of indexes in a fraction of a second. See this [Question about NSPredicate](http://stackoverflow.com/questions/24176605/using-predicate-in-swift). Try working up some code to filter using the NSPredicate and if you get stuck let us know so we can assist. – Jay May 17 '16 at 17:35
  • Thanks @Jay but I'm using both Android and iOS, for now I'm not looking for a solution on client side, I think there has to be a correct way to solve this without relying on the implementation of each client. – RominaV May 17 '16 at 18:09

1 Answers1

1

There are a number of solutions but here's one that's pretty straightforward:

Given the following Firebase structure (left the scores out to simplify)

tournaments
  t_3515 
    entry_fee:100
    status:Active
    players  
      p_3: true
      p_4: true
    status
      P_3: waiting
      P_4: accepted
    }
  }

1) One screen that shows/listens "all" the list of tournaments.

When the user is on the screen that observes all of the tournaments do the following.

ref = tournaments

ref.observeEventType(.Value, withBlock: { snapshot in
    print(snapshot)
    //note that Value returns the entire contents of the node so this is not
    //  the best approach. It's here for conceptual. See note below.
})

This will notify the app of any nodes that change in tournaments

2) One screen with shows/listens the tournaments that the logged user belongs to.

When the user is on the screen that observes only the tournaments they are part of, do the following: Assume the user is p_3 and wants to see what tournaments they are in:

ref = tournaments

ref.queryOrderedByChild("players/p_3").queryEqualToValue(true)
        .observeEventType(.Value, withBlock: { snapshot in
    print(snapshot)
})

When switching between screens, stop observing the prior.

ref.removeAllObservers

Now, to drill down a bit, you will probably not want to use .Value to attach your observers. .ChildAdded, .ChildChanged and .ChildRemoved will give you a better level of granularity with what's actually going on.

Jay
  • 34,438
  • 18
  • 52
  • 81