How To Query, Filter And Sort Firebase Real-Time Database

Firebase Javascript

In this Firebase tutorial, you will learn how to make a query to the Firebase Real-time Database using Firebase events. After that, you will learn how to sort and filter data using Firebase Order Functions.

Finally, I will be showing you how to filter the data using Firebase Query Functions.

Making a query to the Firebase Real-time Database is completely different than traditional SQL queries because Firebase uses NO-SQL Database Structure.

Trust me it’s not that hard! 🙂

Let’s split this article into FOUR parts.

  1. First, NodeJS + Firebase Database Setup process
  2. Then, talking about Firebase Events with examples
  3. After that, diving into Firebase Order Functions for Sorting data
  4. Finally, getting our hands dirty with Firebase Query Functions for Filtering data

1. NodeJS + Firebase Database Setup

STEP #1: Create an app on the Firebase Console:  I have already covered this in one of my other Firebase blogs links below,

• Setting up a Firebase App on the Firebase Console
• Enable Read and Write Permission to the Firebase Database

STEP #2: Import sample JSON file to the Firebase Database.

{
  "users": {
    "-L6sDfnljY_Kd2IOvWu9": {
      "age": "24",
      "email": "ameraz@email.com",
      "name": "Alex Meraz1"
    },
    "-L6sDmT0yPtPFIMOj40s": {
      "age": "22",
      "email": "mrafi@email.com",
      "name": "Mohammand Rafi"
    },
    "-L7q-Sg_SCvs7QOlb7Kh": {
      "age": "31",
      "email": "rtamil@email.com",
      "name": "Raja Tamil"
    },
    "-L7qUZl_fpcmYzJMZK-V": {
      "age": "21",
      "email": "spichai@email.com",
      "name": "Sundar Pichai"
    }
  }
}

Create JSON file with the above code then import into your Firebase Database,

  • Go to DEVELOP → Database → Get Started → DATA Tab.
  • Click the  ⋮  vertical ellipsis icon at the right, then choose import JSON option from the drop-down.
  • Choose the JSON file that you have created with the sample code.

import-json-firebase-database

As you can see, the structure of the database data is just JSON format and in that, I have users node at the top level.

Then inside, I have a few user objects with the alphanumeric unique key which is automatically generated by Firebase when you insert a new user object, this key is called a push key.

Moving on,

If you want to use Browser JavaScript Client instead of Node Client, you can check it out in here. The process is very similar to what I will be doing here in STEP 3.

STEP #3: Setting up the Node.js project,  I know this will involve some Terminal / Command prompt code,

I know some of you hate that as I used to also, but this is not that bad, issuing some command then you’re good to go 🙂

  1. Download & Install Node.js on your computer by going to the Node.js official site.
  2. Open up Terminal and type node –version, if it shows the version number, you have node installed successfully on your computer.
  3. Create a folder on your computer called firebase-query.
  4. In your terminal, change the directory by issuing this command cd firebase-query.
  5. After that, You need to install firebase by issuing this command npm install firebase.
  6. When you open the firebase-query folder in your favorite text editor, you should see the node_modules folder
  7. Then, create an index.js file.
  8. Finally, add the code below inside the file at the top:
var firebase = require("firebase");
firebase.initializeApp({
  databaseURL: "httpss://addyourfirebasedatabaseurl.firebaseio.com/"
});
var dbRef = firebase.database().ref("users");
console.log(dbRef);

In the first line, I import firebase into index.js,

After that, I initialize firebase app using the initializeApp method on the firebase,

This method takes an object as an argument which has only one property for now called databaseURL and replaces the value of the URL with yours.

To get your databaseURL, Go to the Firebase Console -> DEVELOP → Database → DATA Tab → https://yourdatabaseURL.com/

firebase-database-url

dbRef is a reference to the database location path and you can also specify any child node with it, I use users as I am going to unitize the data only inside users node.

Now, open up your terminal and type node index.js to run the file and of courses if everything works, you will get the console.log(dbRef) message printed with the whole bunch of data.

You will need to run the node index.js every time you make some changes in an index.js file to see the result in the terminal window. 

Okay,

2. Querying Data using Firebase Events

Here are the FOUR important Firebase events:

  • value()
  • child_added()
  • child_changed()
  • child_removed()

These events will help you to query data from Firebase Database.

a) Value

Value event will fire whenever there is a change which could be Add/Delete/Edit on the Database Reference in which the value event runs on.

Also, this event will fire on page load for the first time.

firebase-query-value-event

firebase-query-value-event

As I am making changes every time in the database, I get the newly updated snapshot which has a FULL user data object.

All you have to do is to:

1. Create a database reference

const dbRef = firebase.database().ref("users")

2. Then, Attach the value event to it with the method on

dbRef.on("value", snap => {
    console.log(snap); // this key will output users
    console.log(snap.key); // this method will return full user
});

As you can see, I use the on method to observe the value event every-time there is a change in the DB.

Note:

You can use once, off methods as well,

  • Once:  Once method will fire only once unlike on method which will keep listening for database changes.
  • Off: This method will detach the event listener to the database reference

Notes

This on method will take two arguments,

  • Value – Event Name
  • Callback  – The second argument is callback function with the parameter snap which will have all the information that you need from the database.

Once you get the snapshot object, you can iterate through them and render accordingly inside the callback function.

Snapshot object has a lot of properties and methods that you can use. I am going to show you the main THREE things:

  • snap.key: This property will output the root key to the console which would be users in this case
  • snap.val(): This method will return value of users key, so in this case the THREE user objects
  • snap.ref.toString(): This property returns the database reference URL path.

You can find more information about data snapshot here.

I have another way to use the value event using Promises.

3. Working with Promises.

If you’re not sure what is promises, you can watch the video here.

Instead of using callback functions, you can use promises for better multiple asynchronous operations and error handling

Actually console.log(dbRef.once(“value”)); returns promise

dbRef.once("value").then(snap => {
    console.log(snap.val());
}).catch(error => {
    console.log("error".error)
})

The value event is great when you have a small set of data but if you have thousands of user objects, value event will not scale very well.

For a larger dataset, I would use Child_Added which I am going to explain next…

b) Child_Added

On page load, the child_added event will iterate through each user object so that we do not have to loop through them, unlike value event.

Apart from on page load, the child_added event will only fire whenever a new object is to be added to the Database.

In addition to that, you can get only the newly added user object in the callback parameter, not the whole object every time, unlike value event.

As you can see the child_added event is more efficient than value event.

Creating child_added event is very similar to value event.

dbRef.on("child_added", snap => {
    console.log(snap);
});

Note: if you have already created the database reference you can use the same variable over and over again rather than creating a new one every event implementation.

Pretty straightforward…

c) Child_Changed

On page load, the child_changed event will NOT fire unlike value and child_added events.

The child_changed event will only fire if there is any change which includes any value change of any property / removing a specific property in the Firebase Database.

Also, update object will be available in the callback param snap.val(), then you can update and render the view.

creating child_changed is identical to child_added except the name obviously 🙂

dbRef.on("child_changed", snap => {
    console.log(snap.val()); // will return updated user object
});

d) Child_Removed

You have guessed it :),

The child_removed event will fire when there is an object removed completely.

Note: It’s recommended to use child_added, child_changed and child_removed events instead of using value event in your CRUD Web app,

so that you have more control and it will be faster as well as it scales!

All you have to do is to create a local variable and sync with the Firebase database and the rest of them magically will happen.

Next,

3. Sorting Data using Order Functions

Order Functions are great for Sorting Data,

  1. orderByChild()
  2. orderByKey()
  3. orderByValue()

a) orderByChild()

The orderByChild() function is the most useful one and if you have SQL background this is similar to ORDER BY clause.

In the child_added event example, you get user data one by one. Using orderByChild(), you can sort the data by any child (think about the child key as a column name in SQL).

The way you use orderByChild() function is to attach to the database reference before on method and passing the child name in this case age that you want to sort on.

dbRef.orderByChild("age").on("child_added", snap => {
 console.log(snap.val());
});
firebase-query-order-by-child

firebase-query-order-by-child

As you can see, orderByChild() will always be sorted by ascending order.

b) orderByKey()

Before using this order function, I wanted to talk about push key (-L6sDmT0yPtPFIMOj40s) which is a long string with an alphanumeric character that you can see in the sample JSON data as a key for each user object.

Push keys will be generated automatically by the Firebase and every time when adding new data, Firebase will create push key as an id of the user.

Push keys are generated based on the time that the data saved in milliseconds so these keys will be unique similar to id in SQL.

When you query data using any of the firebase events, you will get data orderByKey() by default,  oldest at the top and latest at the bottom.

dbRef.on("child_added", snap => {
    console.log(snap.val());
});

You can learn how push keys are generated and used in my other Firebase CRUD App – Create/Add User Section

c) orderByValue()

I think this will only be used when you have data in a database like below, just key and value pairs:

{
    "L6sDmT0yPtPFIMOj40s": "Apple",
    "L6dsDmTf0yPtPF7MOj4s": "Orange",
}

Then you can use orderByValue() to sort fruits data

dbRef.orderByValue().on("child_added", (snap) => {
    console.log(snap.val());
});

Leave a comment if you find any other way we can use orderByValue() 🙂

Moving on to…

4. Filtering Data using Query Functions

You can make complex Database queries with Firebase Query functions combined with Order functions.

Here are the FIVE important query functions for the filtering purpose.

  1. LimitToFirst(#)
  2. LimitToLast(#)
  3. StartAt()
  4. endAt(#)
  5. equalTo(“child_key”)

LimitToFirst(#)

In the below example, I use limitToFirst with an argument 1. So, this query will return the first object from the top in the database reference. You can change the argument # value based on how many items needed.

dbRef.limitToFirst(1).on("child_added", (snap) => {
    console.log(snap.val());
});

Let’s combine with order function.

dbRef.orderByChild("age").limitToFirst(1).on("child_added", (snap) => {
    console.log(snap.val());
});

The above example, first orders the data in ascending order by child age, then limits the first item based on the top from the order function result using limitToFirst(1).

When you run the above example, you will get a warning like this at the time of writing this article.

FIREBASE WARNING: Using an unspecified index. Your data will be downloaded and filtered on the client. Consider adding “.indexOn”: “email” at /users to your security rules for better performance.

Let’s index the child key age by adding .indexOn security rule in the database under the rules tab.

Go to the Firebase Console -> DEVELOP → Database → RULES tab, then replace with the code below, then hit Publish

{
    "rules": {
        ".read": "true",
        ".write": "true",
        "$uid": {
            ".indexOn": "age",
        }
    }
}

LimitToLast(#)

As you have guessed,

the limitToLast(1) query will return the last object from the bottom of the queried list. You can change the argument # value based on how many items needed.

dbRef.limitToLast(1).on("child_added", (snap) => {
    console.log(snap.val());
});

StartAt(“value”)

StartAt() function will only return the objects from the database after the value specified in an argument in this case “Raja Tamil” matches with the child name.

In the below example,  you will get all the user objects starting from the object that has “Raja Tamil” value of the child key name.

dbRef.orderByChild("name").startAt("Raja Tamil").on("child_added", (snap) => {
    console.log(snap.val());
});

EndAt(“value”)

The endAt() function will only return the user objects from the database until the value specified in an argument in this case “Raja Tamil” matches with the child name.

In the below example,  you will get all the user objects starting from the top until a user object where name:  “Raja Tamil”

dbRef.orderByChild("name").endAt("Raja Tamil").on("child_added", (snap) => {
    console.log(snap.val());
});

EqualTo(“value”)

The equalTo() query function is pretty straightforward and this can be used when you want to get a specific user object by any of the child keys such as age, name, email etc.

In the below example, I use the child name in the order function and put the value that I want it to equal to in the equalTo() function as an argument.

dbRef.orderByChild("name").equalTo("Raja Tamil").on("child_added", (snap) => {
    console.log(snap.val());
});

If you have an SQL background, equalTo() is very similar to WHERE clause.

Conclusion

As I mentioned at the beginning of this article, querying data in Firebase is very simple using Firebase event such as value, child_added, child_changed and child_removed. 

Combining Firebase Events with order functions, such as orderByChld(), orderByKey() and  orderByValue(), help you to sort data anyway you want.

On top of that, filtering data with query functions such as limitToFirst(), limitToLast(), startAt(), endAt() and equalTo() combined with the order functions enable you to create such powerful and complex queries.

What are the queries that you think you can do it in SQL but not in the Firebase?

UP NEXT  → How to Build A Simple CRUD App with Firebase Real-Time Database

Comments Count: 0 0