RobertoCuba
RobertoCuba

Reputation: 901

Firebase - Query by existence of a (grand)child

I have a data path like this

events
    -KntTJCVBtbrb79dHemC
        dateStamp: 1498747689858
        admin: "rPxwIzEtJaRbEH6ujkP5QJgpHDp2"
        attending:
            rPxwIzEtJaRbEH6ujkP5QJgpHDp2: true
            MtaPwHEKMEOTXBRdXBuXuS3gst12: false

I would like to get the events that have certain users attending. In other words, I would like to get all events where the key "attending/[some-user-id]" exists.

Problem is I have only been able to do it by filtering by a specific value of that path (either true or false), like this:

eventsRef.orderByChild("attending/" + user.getId()).equalTo(true).addListenerForSingleValueEvent(...)

That works but only for where the value of the key is true, so to get what I need I have to do 2 calls, one for when the value is true and one for when it is false.

I tried using startAt(true) and endAt(false) (and viceversa) but that ended up returning nothing.

I'm not sure what I am missing.

EDIT

I should have specified that I know this could be done with denormalization and using another node as the relationship 'table', I was just wondering if the above specifically was possible since it is already so close and it would avoid a 2-step process of getting a key first and then retrieving the actual data.

Upvotes: 0

Views: 324

Answers (1)

Rohan Stark
Rohan Stark

Reputation: 2396

Here's when denormalisation of data comes into play!

What you described is the only method to query a grandchild. And of course, as you mentioned, it is not very intuitive, useful or fast.

What you have to do is to create a separate node for the users attending a given event. You can name it something like UsersAttendingTheEvent. This will have the event keys as children. Whenever a user starts attending a given event, add the user key as a child of the event key ( and thus, grandchild of UsersAttendingTheEvent.

So, for example,

UsersAttendingTheEvent:{
 -KntTJCVBtbrb79dHemC:{
        rPxwIzEtJaRbEH6ujkP5QJgpHDp2: true
        MtaPwHEKMEOTXBRdXBuXuS3gst12: false
       }}

Now, when you want to run a query, you can just run a simple orderByChild(userId) query on UsersAttendingTheEvent to obtain all the keys of the events that the user is attending.

Following this, you can obtain the Event details from your main event/eventKey. This might seem like an additional call, but it is how denormalisation of data is designed for Firebase. Plus, it works reasonably fast.

EDIT

The reason your startAt(true) and endAt(false) returned nothing is that when orderByChild() is called, the order in which the items returned are as follows:-

  1. null
  2. false
  3. true
  4. numerically
  5. lexicographically

This is mentioned on this page https://firebase.google.com/docs/database/android/lists-of-data.

Try using only startAt(true). This would work if you make sure that your member keys only have true or false values and no other value would be returned lexicographically after true.

Upvotes: 2

Related Questions