1

I'm trying to do a sample application with firebase and I don't have quite understand how I should retrieve nested-flattered data.

Let's suppose I have a db like this

 {
        "users": {
            "user-1": {
                "email": "email1",
                "matches": [
                    "match-1",
                    "match-2"
                ]
            },
            "user-2": {
                "email": "email2",
                "matches": [
                    "match-1",
                    "match-2"
                ]
            },
            "user-3": {
                "email": "email3",
                "matches": [
                    "match-2"
                ]
            }
        },
        "matches": {
            "match-1": {
                "name": "Match 1",
                "users": [
                    "user-1",
                    "user-2"
                ]
            },
            "match-2": {
                "name": "Match 2",
                "users": [
                    "user-1",
                    "user-2",
                    "user-3"
                ]
            }
        }
    }

and I want to get all the match of the user-1. What I'm doing now is observe users.user-1.matches to get the matches list and then observe every match so the final flow is:

  • observe users.user-1.matches
  • observe matches.match-1
  • observe matches.match-2
  • ...

The question is: how can I optimize this flow? (like making something like the sql join)

My idea is to get something like this

{
    "users": {
        "user-1": {
            "email": "email1",
            "matches": {
                "match-1": {
                    "name": "Match 1",
                    "users": [
                        "user-1",
                        "user-2"
                    ]
                },
                "match-2": {
                    "name": "Match 2",
                    "users": [
                        "user-1",
                        "user-2",
                        "user-3"
                    ]
                }
            }
        }
    }
}

So I can observer the whole structure at once.

I'm using firebase on iOS with swift but feel free to reply in every language you like.

Thanks.

Gnammo
  • 255
  • 2
  • 8
  • See http://stackoverflow.com/questions/40783240/firebase-in-clause-query-and-lists-of-datas/40808561#40808561 (found by [searching for firebase swift questions mentioning 'join'](http://stackoverflow.com/search?q=%5Bfirebase%5D%5Bswift%5D+join)). – Frank van Puffelen Dec 07 '16 at 13:12

1 Answers1

3

The answer linked in the comment is an answer, but let's simplify. Let's create a users node to store the users and a matches node to track the matches they played in.

Then we'll do a query to retrieve which matches user-1 played in:

users
  user-1
    name: "some name"
    email: "somename@thing.com"
  user-2
    name: "another name"
    email: "anothername@thing.com"
  user-3
    name: "cool name"
    email: "coolname@thing.com"

and then the matches node

matches
  match-1
    name: "Match 1"
    users
        user-1: true
        user-2: true
  match-2
    name: "Match 2"
    users
        user-1: true
        user-2: true
        user-3: true
  match-3
    name: "Match 3"
    users
        user-2: true
        user-3: true

As you can see, we've structured the data to directly address our query

matchesRef.queryOrdered(byChild: "users/user-1").queryEqual(toValue: true)
                         .observe(.value, with: { snapshot in
     print(snapshot)          
});

and the snapshot will contain the nodes match-1 and match-2 but not match-3

Jay
  • 34,438
  • 18
  • 52
  • 81
  • with your solution I'm being able to remove the matches reference from the users. Now I have a matches list for every user but, again, I have to observe the players individually to get their properties. (eg: name, email..) – Gnammo Dec 08 '16 at 17:20
  • @Gnammo Right. But. You will need to access that players data individually anyway. For example, suppose you are displaying a list of players to the user in a tableView. The view shows the players the user can tap or click to see the matches they played in. That initial player list has to come from somewhere at some point so when you load the players in initially, also maintain the other relevant data in your tableviewDatasource array. When the user then taps the player, you know their uid (user-1 etc) and can then query the matches for that players matches. – Jay Dec 08 '16 at 17:58
  • Ok, I have a last question: can I filter the matches based on some other property? I'm trying with `matchesRef.queryOrdered(byChild: "users/user-1").queryEqual(toValue: true).queryEqual(toValue: "some name", childKey: "name")` but it causes a crash because "Can't call queryEqualToValue:childKey: after queryStartingAtValue, queryEndingAtValue or queryEqualToValue was previously called" – Gnammo Dec 08 '16 at 18:10
  • @Gnammo Yes, you can query matches for some other property, but only one. i.e. Firebase does not offer a way to query on multiple children. So you cannot do (where user-1 == true and name == frank). There are ways around this and there are a number of posts here about doing Firebase queries with multiple children. See [Mutliple Where Clauses](http://stackoverflow.com/questions/26700924/query-based-on-multiple-where-clauses-in-firebase) – Jay Dec 08 '16 at 18:43
  • Good to know! Well, thank you Jay, you helped me a lot! – Gnammo Dec 09 '16 at 08:26
  • If I understand your question, the answer would be to observeSingleEvent of .value on the /users/user-1 node. That would retrieve all of the child data for user-1 (name, email etc) – Jay May 28 '17 at 14:37
  • (_Deleted the original comment, it should come before the comment above_) @Jay Sorry if this comment is delayed. I am trying to solve a similar issue where I join different nodes but mine works in opposite to your example. Are you able to elaborate how this would work in reverse in regards to finding the information of _users_. So from your example how do I get 'user-1: true`'s email and name? If this question is too off topic then I'll post a new one that is more **specific** – Chace May 28 '17 at 14:39
  • @Jay Thanks for that response. This does get the users details. However I am trying to get details of _users_ depending on the a node they are in. So from your example above in `matches` I only want the _users_ from `match-1` so, `user-1: true` and `user-2` rather then the entire list of _users_. – Chace May 28 '17 at 15:01
  • @Chace Not sure I understand. If you observe the match-1 node, the snapshot will contain a /users child, and in that child there will be two children: user-1: true and user-2: true. If you iterate over that /users node the keys will be user-1 and user-2. Once you have those keys you can observeSingleEvent on the main /users node for /users/uid-1 and /users/uid-2 to get those users details. If that doesn't answer the question, create a new question and link it and we'll take a look. – Jay May 28 '17 at 15:44
  • I see, that's where I'm getting confused. The part where _If you iterate over that /users node the keys will be user-1 and user-2. Once you have those keys you can observeSingleEvent on the main /users node for /users/uid-1 and /users/uid-2 to get those users details_. I thought maybe your response to the answered link isn't detailed enough as over there he explains how to get the **the details of the products** which is essentially what I am trying to achieve. Please correct me if I am wrong. – Chace May 28 '17 at 15:58
  • @Chace This does that. In the above question/answer, we are using users but it could just as well be recipes and ingredients. A recipe node has an /ingredients node with children /ingredients/ingredient_0 and /ingredients/ingredient_1. If you read in the recipe node, the snapshot will contain the /ingredients node. By iterating over the ingredients/ node you can get those two keys, and then in your main /ingredients node observeSingleEvent ingredient_0 and ingredient_1 which will return all of the info for each ingredient. Again, post a question or link to one if you need a specific answer. – Jay May 28 '17 at 16:06
  • @Jay Please see this: https://stackoverflow.com/questions/44230692/how-to-properly-join-two-different-nodes-and-observe-its-values – Chace May 28 '17 at 18:46