'Firebase - How do I write multiple orderByChild for extracting data?

I'm looking to get data where two fields equal what I'm passing in.

Here's an example of my code:

this.refApp
  .orderByChild('userUid')
  .startAt(uid).endAt(uid)
  .orderByChild('jobId')
  .startAt(jobId).endAt(jobId)
  .on('value', (snap) => {
     //This currently doesn't get returned.
  });   

In the above example I don't get any compiler errors and code seems fine. However, I hard coded the data so that it would return an object where uid and jobid are equal to.

I can get this to work for one orderByChild but when I do two like above it doesn't seem to do anything.



Solution 1:[1]

An other way to do kind of multiple orderByChild in Firebase is to create an orderKey.

Imagine you have this in your base:

{
    userId: {
        firstName: 'Jon',
        lastName: 'Snow',
        birthYear: 283
    }
}

And you want to query: userRef.orderByChild('firstName').equalTo('Jon').orderByChild('lastName').equalTo('Snow')

You need to create a key on your user like this:

{
    userId: {
        firstName: 'Snow',
        lastName: 'Jon',
        birthYear: 283,
        orderName: 'JonSnow'
    }
}

So you can query like this: userRef.orderByChild('orderName').equalTo('JonSnow')

This also works with startAt and endAt if you want to query all the Snow born in a range of years. You first create the key:

{
    userId: {
        firstName: 'Snow',
        lastName: 'Jon',
        birthYear: 283,
        orderNameYear: 'Snow283'
    }
}

So you can query: userRef.orderByChild('orderNameYear').startAt('Snow280').endAt('Snow285')

This will return all Snow born between 280 and 285.

Solution 2:[2]

It's not supported.

Depending on the kind of query you need to run on an entity, you will either have to store you jobs by user like @david-east suggested or add a property combining the two properties:

{
 jobId: 'J123',
 userId: 'provider:123',
 jobIdUserIdIndex: 'J123/provider:12345',
 [...]
}

But usually, there are no way to allow all the queries you need. You either have to filter objects on the client side, or duplicate the data to created different view of the data; you will have the job data saved at /jobs/$jobId, /users/$userId/jobs/$jobId and maybe /pendingJobs/$jobId.

I find it's easier to use the orderBy* method only for ordering entities and to duplicate the data to select subsets of them.

I wish Firebase would support indexes combining multiple properties, but for now you need to build those yourself. However having different views allows to apply different security rules to them: e.g. Only one user should have access to /users/$userId/jobs/, only the admin should have access to /jobs/$jobId.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shiv Kumar Baghel
Solution 2