<br />

This document covers working with lists of data in Firebase. To learn the
basics of reading and writing Firebase data see
[Read and Write Data on Android](https://firebase.google.com/docs/database/android/read-and-write).
| **Note:** By default, read and write access to your database is restricted so only authenticated users can read or write data. To get started without setting up [Authentication](https://firebase.google.com/docs/auth), you can [configure your rules for public access](https://firebase.google.com/docs/rules/basics#default_rules_locked_mode). This does make your database open to anyone, even people not using your app, so be sure to restrict your database again when you set up authentication.

## Get a DatabaseReference

To read and write data from the database, you need an instance of `DatabaseReference`:  

### Kotlin

```kotlin
private lateinit var database: DatabaseReference
// ...
database = Firebase.database.reference  
https://github.com/firebase/snippets-android/blob/a413b0658ff2fc7a72c4b0c59e84a889ff7fac45/database/app/src/main/java/com/google/firebase/referencecode/database/kotlin/ReadAndWriteSnippets.kt#L27-L27
```

### Java

```java
private DatabaseReference mDatabase;
// ...
mDatabase = FirebaseDatabase.getInstance().getReference();
```

## Read and write lists

### Append to a list of data

Use the `push()` method to append data to a list in multiuser applications.
The `push()` method generates a unique key every time a new
child is added to the specified Firebase reference. By using these
auto-generated keys for each new element in the list, several clients can
add children to the same location at the same time without write conflicts. The
unique key generated by `push()` is based on a timestamp, so list items are
automatically ordered chronologically.

You can use the reference to the new data returned by the `push()` method to get
the value of the child's auto-generated key or set data for the child. Calling
`getKey()` on a `push()` reference returns the value of the
auto-generated key.

You can use these auto-generated keys to simplify flattening your data
structure. For more information, see the data fan-out
[example](https://firebase.google.com/docs/database/android/structure-data#fanout).

### Listen for child events

When working with lists, your application should listen for child events
rather than the value events used for single objects.

Child events are triggered in response to specific operations that happen to the
children of a node from an operation such as a new child added through the
`push()` method or a child being updated through the `updateChildren()` method.
Each of these together can be useful for listening to changes to a specific node
in a database.

In order to listen for child events on `DatabaseReference`, attach a
`ChildEventListener`:

| Listener | Event callback | Typical usage |
|---|---|---|
| `ChildEventListener` | `onChildAdded()` | Retrieve lists of items or listen for additions to a list of items. This callback is triggered once for each existing child and then again every time a new child is added to the specified path. The `DataSnapshot` passed to the listener contains the the new child's data. |
| `ChildEventListener` | `onChildChanged()` | Listen for changes to the items in a list. This event fired any time a child node is modified, including any modifications to descendants of the child node. The `DataSnapshot` passed to the event listener contains the updated data for the child. |
| `ChildEventListener` | `onChildRemoved()` | Listen for items being removed from a list. The `DataSnapshot` passed to the event callback contains the data for the removed child. |
| `ChildEventListener` | `onChildMoved()` | Listen for changes to the order of items in an ordered list. This event is triggered whenever the `onChildChanged()` callback is triggered by an update that causes reordering of the child. It is used with data that is ordered with `orderByChild` or `orderByValue`. |

For example, a social blogging app might use these methods
together to monitor activity in the comments of a post, as shown below:  

### Kotlin

```kotlin
val childEventListener = object : ChildEventListener {
    override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!)

        // A new comment has been added, add it to the displayed list
        val comment = dataSnapshot.getValue<Comment>()

        // ...
    }

    override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildChanged: ${dataSnapshot.key}")

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        val newComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildRemoved(dataSnapshot: DataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!)

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!)

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        val movedComment = dataSnapshot.getValue<Comment>()
        val commentKey = dataSnapshot.key

        // ...
    }

    override fun onCancelled(databaseError: DatabaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException())
        Toast.makeText(
            context,
            "Failed to load comments.",
            Toast.LENGTH_SHORT,
        ).show()
    }
}
databaseReference.addChildEventListener(childEventListener)
```

### Java

```java
ChildEventListener childEventListener = new ChildEventListener() {
    @Override
    public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());

        // A new comment has been added, add it to the displayed list
        Comment comment = dataSnapshot.getValue(Comment.class);

        // ...
    }

    @Override
    public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so displayed the changed comment.
        Comment newComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildRemoved(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());

        // A comment has changed, use the key to determine if we are displaying this
        // comment and if so remove it.
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
        Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());

        // A comment has changed position, use the key to determine if we are
        // displaying this comment and if so move it.
        Comment movedComment = dataSnapshot.getValue(Comment.class);
        String commentKey = dataSnapshot.getKey();

        // ...
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.w(TAG, "postComments:onCancelled", databaseError.toException());
        Toast.makeText(mContext, "Failed to load comments.",
                Toast.LENGTH_SHORT).show();
    }
};
databaseReference.addChildEventListener(childEventListener);
```

### Listen for value events

While using a `ChildEventListener` is the recommended way to read lists of
data, there are situations where attaching a `ValueEventListener` to a list
reference is useful.

Attaching a `ValueEventListener` to a list of data will return the entire
list of data as a single `DataSnapshot`, which you can then loop over to
access individual children.

Even when there is only a single match for the query, the snapshot is still a
list; it just contains a single item. To access the item, you need to loop
over the result:  

### Kotlin

```kotlin
// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})
```

### Java

```java
// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});
```

This pattern can be useful when you want to fetch all children of a list
in a single operation, rather than listening for additional `onChildAdded`
events.

## Detach listeners

Callbacks are removed by calling the `removeEventListener()` method on your
Firebase database reference.

If a listener has been added multiple times to a data location, it is
called multiple times for each event, and you must detach it the same number of
times to remove it completely.

Calling `removeEventListener()` on a parent listener does not
automatically remove listeners registered on its child nodes;
`removeEventListener()` must also be called on any child listeners
to remove the callback.

## Sorting and filtering data

You can use the Realtime Database `Query` class to retrieve data sorted by
key, by value, or by value of a child. You can also filter
the sorted result to a specific number of results or a range of keys or
values.
| **Note:** Filtering and sorting can be expensive, especially when done on the client. If your app uses queries, define the `.indexOn` rule to index those keys on the server and improve query performance as described in [Indexing Your Data](https://firebase.google.com/docs/database/security/indexing-data).

### Sort data

To retrieve sorted data, start by specifying one of the order-by methods to
determine how results are ordered:

| Method | Usage |
|---|---|
| `orderByChild()` | Order results by the value of a specified child key or nested child path. |
| `orderByKey()` | Order results by child keys. |
| `orderByValue()` | Order results by child values. |

You can only use **one** order-by method at a time. Calling an order-by method
multiple times in the same query throws an error.

The following example demonstrates how you could retrieve a list of a user's
top posts sorted by their star count:  

### Kotlin

```kotlin
// My top posts by number of stars
val myUserId = uid
val myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
    .orderByChild("starCount")

myTopPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})
```

### Java

```java
// My top posts by number of stars
String myUserId = getUid();
Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId)
        .orderByChild("starCount");
myTopPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});
```

This defines a query that when combined with a [child listener](https://firebase.google.com/docs/database/android/lists-of-data#child-events)
synchronizes the client with the user's posts from the path in the database
based on their user ID, ordered by the number of stars each post has received.
This technique of using IDs as index keys is called data fan out, you can read
more about it in
[Structure Your Database](https://firebase.google.com/docs/database/android/structure-data#fanout).

The call to the `orderByChild()` method specifies the child key to order the
results by. In this case, posts are sorted by the value of their respective
`"starCount"` child. Queries can also be ordered by nested
children, in case you have data that looks like this:  

```text
"posts": {
  "ts-functions": {
    "metrics": {
      "views" : 1200000,
      "likes" : 251000,
      "shares": 1200,
    },
    "title" : "Why you should use TypeScript for writing Cloud Functions",
    "author": "Doug",
  },
  "android-arch-3": {
    "metrics": {
      "views" : 900000,
      "likes" : 117000,
      "shares": 144,
    },
    "title" : "Using Android Architecture Components with Firebase Realtime Database (Part 3)",
    "author": "Doug",
  }
},
```

In this example, we can order our list elements by values nested under the
`metrics` key by specifying the relative path to the nested child in our
`orderByChild()` call.  

### Kotlin

```kotlin
// Most viewed posts
val myMostViewedPostsQuery = databaseReference.child("posts")
    .orderByChild("metrics/views")
myMostViewedPostsQuery.addChildEventListener(object : ChildEventListener {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
})
```

### Java

```java
// Most viewed posts
Query myMostViewedPostsQuery = databaseReference.child("posts")
        .orderByChild("metrics/views");
myMostViewedPostsQuery.addChildEventListener(new ChildEventListener() {
    // TODO: implement the ChildEventListener methods as documented above
    // ...
});
```

For more information on how other data types are ordered, see
[How query data is ordered](https://firebase.google.com/docs/database/android/lists-of-data#data-order).

### Filtering data

To filter data, you can combine any of the limit or range methods with an
order-by method when constructing a query.

| Method | Usage |
|---|---|
| `limitToFirst()` | Sets the maximum number of items to return from the beginning of the ordered list of results. |
| `limitToLast()` | Sets the maximum number of items to return from the end of the ordered list of results. |
| `startAt()` | Return items greater than or equal to the specified key or value depending on the order-by method chosen. |
| `startAfter()` | Return items greater than the specified key or value depending on the order-by method chosen. |
| `endAt()` | Return items less than or equal to the specified key or value depending on the order-by method chosen. |
| `endBefore()` | Return items less than the specified key or value depending on the order-by method chosen. |
| `equalTo()` | Return items equal to the specified key or value depending on the order-by method chosen. |

Unlike the order-by methods, you can combine multiple limit or range functions.
For example, you can combine the `startAt()` and `endAt()` methods to limit
the results to a specified range of values.

Even when there is only a single match for the query, the snapshot is still
a list; it just contains a single item. To access the item, you need
to loop over the result:  

### Kotlin

```kotlin
// My top posts by number of stars
myTopPostsQuery.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        for (postSnapshot in dataSnapshot.children) {
            // TODO: handle the post
        }
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
        // ...
    }
})
```

### Java

```java
// My top posts by number of stars
myTopPostsQuery.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
        for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
            // TODO: handle the post
        }
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        // Getting Post failed, log a message
        Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
        // ...
    }
});
```

#### Limit the number of results

You can use the `limitToFirst()` and `limitToLast()` methods to set a
maximum number of children to be synced for a given callback. For example, if
you use `limitToFirst()` to set a limit of 100, you initially only receive up
to 100 `onChildAdded()` callbacks. If you have fewer than 100 items stored in your
Firebase database, an `onChildAdded()` callback fires for each item.

As items change, you receive `onChildAdded()` callbacks for items that enter the
query and `onChildRemoved()` callbacks for items that drop out of it so that
the total number stays at 100.

The following example demonstrates how example blogging app defines a query to
retrieve a list of the 100 most recent posts by all users:  

### Kotlin

```kotlin
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys.
databaseReference.child("posts").limitToFirst(100)
```

### Java

```java
// Last 100 posts, these are automatically the 100 most recent
// due to sorting by push() keys
Query recentPostsQuery = databaseReference.child("posts")
        .limitToFirst(100);
```

This example only defines a query, to actually synchronize data it needs to
have an attached [listener](https://firebase.google.com/docs/database/android/lists-of-data#child-events).

#### Filter by key or value

You can use `startAt()`, `startAfter()`, `endAt()`, `endBefore()`, and
`equalTo()` to choose arbitrary starting, ending, and equivalence points for
queries. This can be useful for paginating data or finding items with children
that have a specific value.

### How query data is ordered

This section explains how data is sorted by each of the order-by methods in the
`Query` class.

#### `orderByChild`

When using `orderByChild()`, data that contains the specified child key is
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](http://en.wikipedia.org/wiki/Lexicographical_order) 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 are sorted lexicographically by key in ascending order.

#### `orderByKey`

When using `orderByKey()` to sort your data, data is returned in ascending order
by key.

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.

#### `orderByValue`

When using `orderByValue()`, children are ordered by their value. The ordering
criteria are the same as in `orderByChild()`, except the value of the node is
used instead of the value of a specified child key.

## Next steps

- [Learn how to structure data](https://firebase.google.com/docs/database/android/structure-data)
- [Store data offline](https://firebase.google.com/docs/database/android/offline-capabilities)