Retrieving Data

Reading Data with GET

We can read data from our Firebase database by issuing a GET request to its URL endpoint. Let's continue with our blog example from the previous section and read all of our blog post data:

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'

A successful request will be indicated by a 200 OK HTTP status code, and the response will contain the data we're retrieving.

Adding URI Parameters

The REST API accepts several query parameters when reading data from our Firebase database. Listed below are the most commonly used parameters. For a full list, refer to the REST API Reference.

auth

The auth request parameter allows access to data protected by Firebase Realtime Database Security Rules, and is supported by all request types. The argument can either be your Firebase app's secret or an authentication token, as described in the Users in Firebase Projects. In the following example we send a GET request with an auth parameter, where CREDENTIAL is either your Firebase app's secret or an authentication token:

curl 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

print

Specifying print=pretty returns the data in a human-readable format.

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=pretty'

Specifying print=silent returns a 204 No Content on success.

curl 'https://docs-examples.firebaseio.com/fireblog/posts.json?print=silent'

callback

To make REST calls from a web browser across domains you can use JSONP to wrap the response in a JavaScript callback function. Add callback= to have the REST API wrap the returned data in the callback function you specify. For example:

<script>
  function gotData(data) {
    console.log(data);
  }
</script>
<script src="https://docs-examples.firebaseio.com/fireblog/posts.json?callback=gotData">

shallow

This is an advanced feature, designed to help you work with large datasets without needing to download everything. To use it, add shallow=true as a parameter. This will limit the depth of the data returned. If the data at the location is a JSON primitive (string, number, or boolean) its value will simply be returned. If the data snapshot at the location is a JSON object, the values for each key will be truncated to true. For example, using the data below:

{
  "message": {
    "user": {
      "name": "Chris"
    },
    "body": "Hello!"
  }
}

// A request to /message.json?shallow=true
// would return the following:
{
  "user": true,
  "body": true
}

// A request to /message/body.json?shallow=true
// would simply return:
"Hello!"

Try it out with this curl request:

curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?shallow=true&print=pretty'

timeout

Use this to limit how long the read takes on the server side. If a read request doesn't finish within the allotted time, it terminates with an HTTP 400 error. This is particularly useful when you expect a small data transfer and don't want to wait too long to fetch a potentially huge subtree. Actual read time might vary based on data size and caching.

Specify timeouts using the following format: 3ms, 3s, or 3min, with a number and a unit. If not specified, the maximum timeout of 15min will be applied. If the timeout is not positive, or exceeds the maximum, the request will be rejected with an HTTP 400 error. In the following example, the GET request includes a timeout of 10 seconds.

curl 'https://docs-examples.firebaseio.com/rest/retrieving-data.json?timeout=10s'

Filtering Data

We can construct queries to filter data based on various factors. To start, you specify how you want your data to be filtered using the orderBy parameter. Then, you combine orderBy with any of the other five parameters: limitToFirst, limitToLast, startAt, endAt, and equalTo.

Since all of us at Firebase think dinosaurs are pretty cool, we'll use a snippet from a sample database of dinosaur facts to demonstrate how you can filter data:

{
  "lambeosaurus": {
    "height": 2.1,
    "length": 12.5,
    "weight": 5000
  },
  "stegosaurus": {
    "height": 4,
    "length": 9,
    "weight": 2500
  }
}

We can filter data in one of three ways: by child key, by key, or by value. A query starts with one of these parameters, and then must be combined with one or more of the following parameters: startAt, endAt, limitToFirst, limitToLast, or equalTo.

Filtering by a specified child key

We can filter nodes by a common child key by passing that key to the orderBy parameter. For example, to retrieve all dinosaurs with a height greater than 3, we can do the following:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'

Any node that does not have the child key we're filtering on will be sorted with a value of null. For details on how data is ordered, see How Data is Ordered.

Firebase also supports queries ordered by deeply nested children, rather than only children one level down. This is useful if you have deeply nested data like this:

{
  "lambeosaurus": {
    "dimensions": {
      "height" : 2.1,
      "length" : 12.5,
      "weight": 5000
    }
  },
  "stegosaurus": {
    "dimensions": {
      "height" : 4,
      "length" : 9,
      "weight" : 2500
    }
  }
}

To query the height now, we use the full path to the object rather than a single key:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="dimensions/height"&startAt=3&print=pretty'

Queries can only filter by one key at a time. Using the orderBy parameter multiple times on the same request throws an error.

Filtering by key

We can also filter nodes by their keys using the orderBy="$key" parameter. The following example retrieves all dinosaurs with a name starting with the letter a through m:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="a"&endAt="m"&print=pretty'

Filtering by value

We can filter nodes by the value of their child keys using the orderBy="$value" parameter. Let's say the dinosaurs are having a dino sports competition and we're keeping track of their scores in the following format:

{
  "scores": {
    "bruhathkayosaurus": 55,
    "lambeosaurus": 21,
    "linhenykus": 80,
    "pterodactyl": 93,
    "stegosaurus": 5,
    "triceratops": 22
  }
}

To retrieve all dinosaurs with a score higher than 50, we could make the following request:

curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&startAt=50&print=pretty'

See How Data is Ordered for an explanation on how null, boolean, string, and object values are sorted when using orderBy="$value".

Complex Filtering

We can combine multiple parameters to construct more complex queries.

Limit Queries

The limitToFirst and limitToLast parameters are used to set a maximum number of children for which to receive data. If we set a limit of 100, we will only receive up to 100 matching children. If we have less than 100 messages stored in our database, we will receive every child. However, if we have over 100 messages, we will only receive data for 100 of those messages. These will be the first 100 ordered messages if we are using limitToFirst or the last 100 ordered messages if we are using limitToLast.

Using our dinosaur facts database and orderBy, we can find the two heaviest dinosaurs:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="weight"&limitToLast=2&print=pretty'

Similarly, we can find the two shortest dinosaurs by using limitToFirst:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&limitToFirst=2&print=pretty'

We can also conduct limit queries with orderBy="$value". If we want to create a leaderboard with the top three highest scoring dino sports competitors, we could do the following:

curl 'https://dinosaur-facts.firebaseio.com/scores.json?orderBy="$value"&limitToLast=3&print=pretty'

Range Queries

Using startAt, endAt, and equalTo allows us to choose arbitrary starting and ending points for our queries. For example, if we wanted to find all dinosaurs that are at least three meters tall, we can combine orderBy and startAt:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="height"&startAt=3&print=pretty'

We can use endAt to find all dinosaurs whose names come before Pterodactyl lexicographically:

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&endAt="pterodactyl"&print=pretty'

We can combine startAt and endAt to limit both ends of our query. The following example finds all dinosaurs whose name starts with the letter "b":

curl 'https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy="$key"&startAt="b"&endAt="b\uf8ff"&print=pretty'

Range queries are also useful when you need to paginate your data.

Putting it all together

We can combine all of these techniques to create complex queries. For example, maybe you want to find the name of all dinosaurs that are shorter than or equal in height to our favorite kind, Stegosaurus:

MY_FAV_DINO_HEIGHT=`curl "https://dinosaur-facts.firebaseio.com/dinosaurs/stegosaurus/height.json"`
curl "https://dinosaur-facts.firebaseio.com/dinosaurs.json?orderBy=\"height\"&endAt=${MY_FAV_DINO_HEIGHT}&print=pretty"

How Data is Ordered

This section explains how your data is ordered when using each of the three filtering parameters.

orderBy

When using orderBy with the name of a child key, data that contains the specified child key will be ordered as follows:

  1. Children with a null value for the specified child key come first.
  2. Children with a value of false for the specified child key come next. If multiple children have a value of false, they are sorted lexicographically by key.
  3. Children with a value of true for the specified child key come next. If multiple children have a value of true, they are sorted lexicographically by key.
  4. Children with a numeric value come next, sorted in ascending order. If multiple children have the same numerical value for the specified child node, they are sorted by key.
  5. Strings come after numbers, and are sorted lexicographically in ascending order. If multiple children have the same value for the specified child node, they are ordered lexicographically by key.
  6. Objects come last, and sorted lexicographically by key in ascending order.
The filtered results are returned unordered. If the order of your data is important you should sort the results in your application after they are returned from Firebase.

orderBy="$key"

When using the orderBy="$key" parameter to sort your data, data will be returned in ascending order by key as follows. Keep in mind that keys can only be strings.

  1. Children with a key that can be parsed as a 32-bit integer come first, sorted in ascending order.
  2. Children with a string value as their key come next, sorted lexicographically in ascending order.

orderBy="$value"

When using the orderBy="$value" parameter to sort your data, children will be ordered by their value. The ordering criteria is the same as data ordered by a child key, except the value of the node is used instead of the value of a specified child key.

orderBy="$priority"

When using the orderBy="$priority" parameter to sort your data, the ordering of children is determined by their priority and key as follows. Keep in mind that priority values can only be numbers or strings.

  1. Children with no priority (the default) come first.
  2. Children with a number as their priority come next. They are sorted numerically by priority, small to large.
  3. Children with a string as their priority come last. They are sorted lexicographically by priority.
  4. Whenever two children have the same priority (including no priority), they are sorted by key. Numeric keys come first (sorted numerically), followed by the remaining keys (sorted lexicographically).

For more information on priorities, see the API reference.

Streaming from the REST API

Firebase REST endpoints support the EventSource / Server-Sent Events protocol, making it easy to stream changes to a single location in our Firebase database.

To get started with streaming, we will need to do the following:

  1. Set the client's Accept header to text/event-stream
  2. Respect HTTP Redirects, in particular HTTP status code 307
  3. Include the auth query parameter if the Firebase database location requires permission to read

In return, the server will send named events as the state of the data at the requested URL changes. The structure of these messages conforms to the EventSource protocol:

event: event name
data: JSON encoded data payload

The server may send the following events:

put The JSON-encoded data will be an object with two keys: path and data
The path points to a location relative to the request URL
The client should replace all of the data at that location in its cache with the data given in the message
patch The JSON-encoded data will be an object with two keys: path and data
The path points to a location relative to the request URL
For each key in the data, the client should replace the corresponding key in its cache with the data for that key in the message
keep-alive The data for this event is null, no action is required
cancel The data for this event is null
This event will be sent if the Firebase Realtime Database Security Rules cause a read at the requested location to no longer be allowed
auth_revoked The data for this event is a string indicating that a the credential has expired
This event will be sent when the supplied auth parameter is no longer valid

Below is an example of a set of events that the server may send:

// Set your entire cache to {"a": 1, "b": 2}
event: put
data: {"path": "/", "data": {"a": 1, "b": 2}}


// Put the new data in your cache under the key 'c', so that the complete cache now looks like:
// {"a": 1, "b": 2, "c": {"foo": true, "bar": false}}
event: put
data: {"path": "/c", "data": {"foo": true, "bar": false}}


// For each key in the data, update (or add) the corresponding key in your cache at path /c,
// for a final cache of: {"a": 1, "b": 2, "c": {"foo": 3, "bar": false, "baz": 4}}
event: patch
data: {"path": "/c", "data": {"foo": 3, "baz": 4}}

If you're using Go, check out Firego, a third-party wrapper around the Firebase REST and Streaming APIs.