Get a database reference
To read or write data from the database, you need an instance of
DatabaseReference
:
DatabaseReference ref = FirebaseDatabase.instance.ref();
Reading and writing 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. The
.key
property of a
push()
reference contains 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
.
For example,
push()
could be used to add a new post to a list of posts
in a social application:
DatabaseReference postListRef = FirebaseDatabase.instance.ref("posts");
DatabaseReference newPostRef = postListRef.push();
newPostRef.set({
// ...
});
Listen for child events
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
update()
method.
Event
|
Typical usage
|
onChildAdded
|
Retrieve lists of items or listen for additions to a list of items.
This event is triggered once for each existing child and then again
every time a new child is added to the specified path. The listener is
passed a snapshot containing the new child's data.
|
onChildChanged
|
Listen for changes to the items in a list.
This event is triggered any time a child node is modified. This includes
any modifications to descendants of the child node. The snapshot passed
to the event listener contains the updated data for the child.
|
onChildRemoved
|
Listen for items being removed from a list. This event is triggered when
an immediate child is removed.The snapshot passed to the callback block
contains the data for the removed child.
|
onChildMoved
|
Listen for changes to the order of items in an ordered list.
onChildMoved events always follow the
onChildChanged event that caused the item's order to
change (based on your current order-by method).
|
Each of these together can be useful for listening to changes to a specific
node in a database. For example, a social blogging app might use these methods
together to monitor activity in the comments of a post, as shown below:
final commentsRef = FirebaseDatabase.instance.ref("post-comments/$postId");
commentsRef.onChildAdded.listen((event) {
// A new comment has been added, so add it to the displayed list.
});
commentsRef.onChildChanged.listen((event) {
// A comment has changed; use the key to determine if we are displaying this
// comment and if so displayed the changed comment.
});
commentsRef.onChildRemoved.listen((event) {
// A comment has been removed; use the key to determine if we are displaying
// this comment and if so remove it.
});
Listen for value events
While listening for child events is the recommended way to read lists of data,
there are situations listening for value events on a list reference is useful.
Attaching a
value
listener to a list of data will return the
entire list of data as a single snapshot 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:
myTopPostsQuery.onValue.listen((event) {
for (final child in event.snapshot.children) {
// Handle the post.
}
}, onError: (error) {
// Error.
});
This pattern can be useful when you want to fetch all children of a list
in a single operation, rather than listening for additional child added
events.
Sorting and filtering data
You can use the
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.
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:
final myUserId = FirebaseAuth.instance.currentUser?.uid;
final topUserPostsRef = FirebaseDatabase.instance
.ref("user-posts/$myUserId")
.orderByChild("starCount");
This defines a query that when combined with a
child listener
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
.
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:
"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 case, 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.
final mostViewedPosts =
FirebaseDatabase.instance.ref('posts').orderByChild('metrics/views');
For more information on how other data types are ordered,
see
How query data is ordered
.
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.
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 event. For example, if
you use
limitToFirst()
to set a limit of 100, you initially only receive up
to 100
onChildAdded
events. If you have fewer than 100 items stored in your
Firebase database, a
onChildAdded
event fires for each item.
As items change, you receive
onChildAdded
events for items that enter the
query and
onChildRemoved
events 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:
final recentPostsRef = FirebaseDatabase.instance.ref('posts').limitToLast(100);
This example only defines a query, to actually synchronize data it needs to
have an attached
listener
.
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:
- Children with a
null
value for the specified child key come
first.
- 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.
- 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.
- 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.
- 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.
- 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.
- Children with a key that can be parsed as a 32-bit integer come first, sorted in ascending order.
- 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.
Detach listeners
Callbacks are removed by calling the
off()
method on your
Firebase database reference.
You can remove a single listener by passing it as a parameter to
off()
.
Calling
off()
on the location with no arguments removes all listeners at that
location.
Calling
off()
on a parent listener does not
automatically remove listeners registered on its child nodes;
off()
must also be called on any child listeners
to remove the callback.
Next steps