Working with Firebase Realtime Database Lists – Techotopia

PreviousTable of ContentsNext Firebase Realtime Database RulesA basic tutorial of Firebase Realtime Database

So far we have only looked at reading and writing individual data items within Firebase Realtime Database. Firebase also provides support for working with lists of data within the database tree. This system allows you to append and delete items from a list, and also perform query operations to extract one or more items from a list based on filtering and matching criteria.

The key elements of handling Firebase database lists are the push() method, the

Query class, child and value event listeners, and a variety of filtering options

.

This chapter will provide an overview of working with lists with Firebase Realtime Database in preparation for the tutorial described in a later chapter titled A Firebase Realtime Database List Data Tutorial.

The push()

method As with all real-time database deployments, an application must first obtain a DB reference instance before working with lists:

FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference dbRef = database.getReference(“/data”);

The push() method of the database reference allows you to append child nodes to a list of database items. Each time the push() method is called, it creates a new node in the path location of the reference instance of the database and assigns it an automatically generated key. This key is unique and includes timestamp information so that all keys in the list are automatically sorted based on the time of creation.

After the push method has created a new child item, it returns an initialized DatabaseReference object with the path to that child item. Calling the getKey() method in this reference will return the automatically generated key that can then be used to store a corresponding value.

The following code, for example, uses the push() method to add a new child element to the path stored in the reference instance of the database:

DatabaseReference newChildRef = dbRef.push();

With access to the database reference for the new child, you can obtain the corresponding key and use it to store a value as follows:

String key = newChildRef.getKey(); dbRef.child(key).setValue(“An item”);

When run, the database tree created by this code will resemble the following:

Figure 23-1

The code to perform the insert operation can be simplified in several ways. One option is to extract the key directly from the database reference: String key

= dbRef.push().getKey(); dbRef.child(key).setValue(“An item”);

Alternatively, you can call the setValue() method on the reference instance of the database for the new child:

DatabaseReference newChildRef = dbRef.push(); newChildRef.setValue(“One item”);

Each time the push() method is called, it will create a new node with a unique key that can be used to store a data value. Figure 23 2, for example, shows multiple children attached to the list using this technique:

Firebase database lists tree 2.png

Figure 23-2

Using Firebase to generate unique keys in this way is also particularly useful when an application has multiple users creating child nodes in the same tree path. Since each key is guaranteed to be unique, there is no risk of multiple users trying to save data using the same key.

In

addition to being able to append child items to a database list, it is also important that an application be notified when changes occur within the list. This can be achieved by setting up event listeners. The use of the value event listener has been described in previous chapters. As the name suggests, a value event listener is triggered when the value stored in a database tree node changes. In addition to value event listeners, working with Firebase Realtime Database lists will typically also require the use of secondary event listeners. These listeners notify the application when child nodes are added, deleted, or moved within a list.

Child event

listeners are created as instances of the ChildEventListener class and added by calling the addChildEventListener() method of the database reference instance.

The following callback methods must be implemented within the child event listener:

onChildAdded(): This method is called whenever a new child is added to a list. When the method is called, a DataSnapshot object containing the newly added data is passed.

onChildChanged(): Called when the data assigned to a node in the list changes or new children are added to that node. When called, the method is passed a DataSnapshot instance that contains the changed data.

onChildRemoved(): When a child node is removed from a list, this method is called and a DataSnapshot object containing the data from the deleted node is passed

.

onChildMoved() – This method is called when any change results in alterations in the order of items in a list.

The following code declares and then adds a child event listener to a database reference:

ChildEventListener childListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onCancelled(DatabaseError databaseError) { } }; dbRef.addChildEventListener(childListener);

When no longer needed, the secondary event listeners should be removed from the database reference:

dbRef.removeEventListener(childListener);

Perform list queries

The Firebase Query class enables apps to retrieve items from a database list based on specified criteria. A range of query options are available, including retrieving items from a list in a certain order or retrieving only certain items based on data matching. Options are also available to control the number and position of list items to retrieve (for example, the first three or last four items in a list).

Once a query has been configured, an event listener is attached that will be called when the operation is complete. The listener will be passed a DataSnapshot object that contains the query data result.

Consider, for example, a structured list as illustrated in Figure 23 3 consisting

of keys generated by the push() method, each of which has a child node consisting of a key/value pair: Figure 23-3

The items are listed in the order in which they were appended to the list, starting with the oldest entry at the top. To retrieve these items from the list in chronological order, the query would have to be configured using sort by key (since the push() method included timestamp information on the keys as the items were appended to the list). Therefore, the code to initialize the query would be as follows: Query query

= dbRef.orderByKey(); query.addListenerForSingleValueEvent(queryValueListener);

Note The event listener was added by using the single-value event listener method. Because queries are typically one-time events, this is more convenient than having to remove the listener after the query completes.

The queryValueListener

referenced in the preceding code might be implemented as follows: ValueEventListener queryValueListener = new ValueEventListener

() { @Override public void onDataChange(DataSnapshot dataSnapshot) { Iterable<DataSnapshot> snapshotIterator = dataSnapshot.getChildren(); Iterator<DataSnapshot> iterator = snapshotIterator.iterator(); while (iterator.hasNext()) { DataSnapshot next = (DataSnapshot) iterator.next(); Log.i(TAG, “Value = ” + next.child(“name”).getValue()); } } @Override public void onCancelled(DatabaseError databaseError) { } };

The onDataChanged() callback method is passed a DataSnapshot object that contains all the children that match the query. As previously implemented, the method iterates through the children, sending the name value for each node to the logcat console. Assuming the list of data shown in Figure 23 3 above, the result would be as follows

: Ethan Alex Dan Chris Bill

To retrieve the data sorted by values, a sort by child query must be performed by referencing the “name” key on the child nodes: Query query

= dbRef.orderByChild(“name”);

When executed, the names will be retrieved and generated in alphabetical order:

Alex Bill Chris Dan Ethan

Items that match the specified criteria can be retrieved using the equalTo() filter. The following code will extract only list items that match the

name “Chris”: Query query = dbRef.orderByChild(“name”).equalTo(“Chris”);

Segments in the list can also be retrieved using the startAt() and endAt() filters. These filters can be used independently or, as in the following example, combined to specify the start and end points:

Query query = dbRef.orderByChild(“name”).startAt(“Bill”).endAt(“Dan”);

The above query, when performed on the list of example names, will generate the following output (note that the order by child is still being used, so the results are presented in alphabetical order):

Bill Chris Dan

You can retrieve specific numbers of list items using the limitToFirst() and limitToLast() filters. Unlike start and end filters, these filters cannot be combined into a single query operation. In the following example, only the first two list entries will be retrieved:

Query query = dbRef.orderByChild(“name”).limitToFirst(2);

Queries and indexes

If an application is expected to query the database frequently, it is important to declare the appropriate indexing rules to maintain database performance. This is accomplished by using the .onIndex rule type, as described in the Firebase Real-Time Database Rules chapter of this book.

Summary

In addition to reading and writing individual data items, Firebase also includes support for working with data in list form. When working with lists, new items are appended to a list using the push() method of the DatabaseReference class. This method creates a child node with an automatically generated key to which data can be written. The Query class, when combined with child and value event listeners, enables you to perform a wide range of query and filtering operations on lists of data stored with Firebase Realtime Database.

PreviousTable of ContentsNext Firebase Realtime Database RulesA Basic Firebase Realtime Database Tutorial