Cloud Firestore

How to Use Firebase Database on Android (Visual Guide)

Pinterest LinkedIn Tumblr

Do you want to know how you can use the Firebase Database on Android? You’ve come to the right place.

Here is what happens to me when I talk about Databases.

 

At the end of the guide, you’ll be able to answer the following questions:

  • How to use Firebase Realtime Database
  • How to query Firebase Realtime Database
  • How to structure Firebase Realtime Database
  • How does Firebase Realtime Database work
  • How to retrieve data from Firebase Realtime Database in Android
  • How to read Data from Firebase Realtime Database Android

Check out this table of content first; so that you can jump to the part you need most:

Quick Jumps

What is Firebase Database?

Firebase Database is a cloud database for your mobile and web applications. You can save and retrieve data from Firebase Database by using the API’s provided by Firebase.

Related: What is Firebase Analytics

I demonstrate that with an example.

There are actually two types of Databases provided by Firebase Database:

  1. Firebase Realtime Database
  2. Firebase Cloud Firestore

Both of these are efficient, scalable, reliable, and NoSQL databases.

Firebase Realtime Database saves data in JSON objects and provides it to all connected clients in real-time.

Why Firebase is Used? 5 Major Uses You’ll Fall in Love With

Firebase Cloud Firestore saves data in the forms of documents and collections and it also syncs through connected clients/devices in realtime.

You can implement both of these databases in an Android App for your demonstration purpose.

What is Firebase Realtime Database?

The definition of Firebase Realtime Database could be:

Firebase Realtime Database is a cloud-hosted NoSQL Database, which can be accessed and used by Android, iOS and Web apps. It stores data in JSON format and any modification made by any platform will be reflected in all connected clients.

In other words, Firebase Realtime uses JavaScript Object Notation JSON to store and retrieve data, which means it contains no tables like structure like SQL but keys and values; these values can contain other keys and values and so on.

Firebase Realtime Database also provides other necessary services like defining rules for your database, making a backup, and analyzing the usage.

A little about JSON Structure

All of the Firebase Realtime Database data is stored in a big JSON tree, which can contain JSON Objects in JSON Objects, Array, and values a lot more. JSON Object always starts with “{” and end with “}”, for example:

JSON example
JSON demo

The above image contains a JSON object thus starting with { (left braces), inside that JSON Object there is another JSON Object named “demo”, inside demo the value 123 assigned to “Test” and “Value 2” assigned to “Test 2”. This is how JSON works and the Firebase Realtime Database uses this mechanism to store data.

Let me clarify to you with an example. I have written code (also explained below) which is creating a database like this in Firebase Realtime Database

Firebase Console Screenshot
Firebase Realtime Database Screenshot

And when I click the three dots in the top right and hit “Export JSON” option:

Steps to export JSON file from Firebase Console
Steps to export JSON from your Firebase Realtime Database console

This is how the exported JSON file looks like:

JSON Screenshot
Exported JSON from Firebase Realtime Database screenshot

I hope you know you have a clear understanding of what Firebase Realtime Database works with JSON.

What Are Firebase Realtime Database Rules?

Afterall Firebase Realtime Database is a database, and you should be careful regarding its security.

So, Firebase provides a clean interface in this regard. You can see a tab named “Rules” in the Firebase Realtime Database window.

Firebase Realtime Database Rules Screenshot
Firebase Realtime Database Rules Screenshot

Just open that tab and you can type the rules the way that suits. Some sample rules are as below:

  • Default Rule

By default, all rules are set in such a way that no-one can read or write to your database. The database can be accessed from Firebase Console only.

  • Public Rule

It means anyone can access your database. It is risky and you should not move to the product with these rules. Must update them before rolling out for production

  • User rule

This is a common scenario, where users have access to their private data only. When a user is authenticated using Firebase Authentication, it’s given a unique ID called UID. And when some data is generated by the user, it is stored under that UID node. So the following rule makes sure that every user has access to his private data only.

You can learn more about Firebase Realtime Database Rules if you want to code real complex rules.

How to Connect An Android Project to Firebase Realtime Database?

Okay, so now you have a little know-how of Firebase Realtime Database features and structure.

So it’s time to start writing and reading your database to Firebase Realtime Database.

First thing first, you need to connect your Android Project to Firebase, and for that, you need a Google account.

There are two ways to connect your project with Firebase.

One is manual; which means you have to manually add the dependency into Android Studio and manually add an app to Firebase Console.

The other is using a plugin, it is provided by Firebase and pre-installed in the latest versions of Android Studio, and does pretty much automatically.

We will use the plugin, but if you want to dive deep into how this plugin does this; you should connect using the manual way.

Connecting your app to Firebase

Here is how you can connect your project to Firebase

  • Open Android Studio
  • Create a New Project
  • Select any pre-defined templates; I am going with Empty Activity. Hit Next.
Choosing Project Android Studio Screenshot
Choosing Project Android Studio Screenshot
  • Configure your project by providing App Name, Package Name, Save Location, Language and Minimum API Level, for the demonstration purpose; I am leaving everything default. Hit Finish.
Configuring Android Studio Project Screenshot
Configuring Android Studio Project Screenshot
  • It will take a few moments to do a new project for you. When completed, go to the Tools menu, and select Firebase
Selecting Firebase Plugin Android studio screenshot
Selecting Firebase Plugin Android Studio screenshot
  • It will open a pane on the right side, where many of Firebase Products will be mentioned, but we are interested in Realtime Database only, so we will expand that and click “Save and retrieve data.
Firebase Pane in Android Studio
Firebase Assistant in Android Studio Screenshot
  • Now the first step you will see is “Connect your App to Firebase” with a button”Connect to Firebase“; hit that. You need to be signed in to Android Studio with your Google account, or Android Studio will divert you to chrome (or any default browser) to log in first.
  • After logged in, a dialogue will be shown asking if you want to connect your app to an existing project or you can create a new project. After you chose any of them, hit Finish. Now, Android Studio will add Firebase dependencies to your project and sync it. It can take a few minutes. Once completed, your project will be connected to Firebase
Selecting Project Window Firebase
Firebase Selecting project window

Connecting Your App to Firebase Realtime Database.

If your project is connected to Firebase, then connecting to Firebase Realtime Database is easy.

The assistant pane – where you connected your app to Firebase – contains a button “Add the Realtime Database to your App” just click that and your app will be connected to Firebase Realtime Database of that particular project that you choose/made for this app.

Adding Firebase Realtime Database in Android

Writing Data to Firebase Realtime Database

After everything is set up, you can now start writing code to save and retrieve data from Firebase Realtime Database.

The first thing that you need to perform any kind of operation is the instance of the Database. This is quite easy, all you need to do is write the following code and you will have the instance to Firebase Realtime Database.

Now that you have an instance of a database, you need a reference where you want to store your data.

You can think of a reference as a path too. By using the following line of code, you will have the reference of the root node of the entire Firebase Realtime Database – the one at the top of JSON Tree.

You can provide any node name to the above getInstance() method, if that node exists; it will return its reference. If not, then a new node with that given string argument will be created.

After getting the reference to the place where you want to write your data, you can start writing it. There are multiple ways to write data to a reference.

  • Writing a value to the root node in the Firebase Realtime Database

If you just call setValue() function to the reference we created above then it will change the value of the root node, i.e. using this code snippet:

You will get something like this in the Firebase Console:

Firebase Console Screenshot
Firebase Realtime Database Console Screenshot

As in this case, our reference was pointing to the root node so setValue() function changed the value of that. Similarly, we can change the value of any node by getting its reference.

If you want to listen to the results of the writing (setting Value) task that you performed to confirm whether the values were written on not, then that’s simple.

The setValue() function returns a Task class object, so you can save that object, or you can simply call addOnCompleteListener() and listen to the results as below:

  • Creating a child in Firebase Realtime Database

It’s not usual that you just need to write one value to Firebase Realtime Database and retrieve it, like if you set a value to the root node, then that node can not contain anything else but that value. So we don’t want to write the value to that root node and end the capability of expanding it, but we create its children and set the value to those children. It can contain multiple children; here is how we do that:

This is how it will be shown in the Firebase Console:

Adding child to Firebase Realtime database console
Firebase Console Realtime Database child

The child method returns the reference, so we called a setValue() function on that reference which created that child and set its value. If that child already exists, then its value will be updated. And again, as we called setValue() function, we already know that it returns a Task object, so we can perform a check here too regarding the results of the creation of the child.

  • Writing an object to Firebase Realtime Database

There will be cases when you can no more write the values separately to Firebase realtime databases like you want to put the data of users into Firebase Realtime Database, so you won’t be calling setValue() function for each of the users attribute. Firebase is already aware of this situation, they provide the exact interface to handle this situation.

You can create a class with a public getter and setters along with a default constructor (which takes no argument) and push that class object straight into the Firebase Database.

For example, I have created this User class with public constructor, getter and setters

I intentionally create the following Date class to store the Date of Birth of the user, this is not a good way to store data, but it’s okay for the demonstration purpose

Okay so now, I can create an object of User class, set the values and I can write it to firebase realtime database with following code snippets

This is how it will be stored in Firebase Realtime Database,

Writing object to Firebase Realtime Database
Writing object to Firebase realtime database screenshot

It created another JSON object for the date class object and assigned the values. This is how we can store objects in an object to Firebase Realtime Database.

Possibilities are endless, you can create any type of complex data for your app, but not only you should know how to write databases but also how to read from the database. And that’s exactly what our next step is.

How to Read Data from Firebase Realtime Database.

Reading and writing are of equal importance, if you know how to write data but don’t know how to read, then there is no use of writing it. So I will show you how you can read data from Firebase Database, it is quite easy.

As I mentioned earlier, either you want to read or write, you definitely need Database reference and for that, you need the instance of Database, so go ahead create those first.

  • Reading Single value from Firebase Realtime Database

Now, I am going to read the value of this “child 1” from the following database:

 

Adding Chil
Firebase Console Realtime Database child

And for that, you need a reference pointing directly to the “child 1” node; here is how you create that

Now, the myRef object contains a reference to “child 1” you can add a listener called addValueEventListener(). Which will be called first, to get the initial value, second when something is changed in that particular database. Here is how you do that

And you will see “I am a child” in a toast message on your android device. And if due to some reason like permission denied or no internet connection, onCancelled will be called and you can get the error message by using the code above.

  • How to read an object from the Firebase Realtime Database

As writing each value separately is a tedious task, the same is the case with reading. Firebase provided the interface for reading a whole JSON object at once; here is how you can do that.

You need a reference for sure, so get a reference to your object first. I am going to read the User object that we wrote to Firebase Database earlier:

Writing object to Firebase Realtime Database
Reading object from Firebase realtime database screenshot

Here is the complete code of reading a whole object from Firebase Realtime Database

It is simple and easy interacting with Firebase Realtime Database. The best part: if your app is closed by the user and some data is changed in the Firebase Realtime Database through Firebase console or any other client; even then the above onDataChange will be called, so if it is a chat application that you are building then you can notify the user that a new message has arrived.

  • Reading Multiple Child from Firebase Realtime Database

There could be many cases when we need to go through all the children in order to find the one we are interested in. Here I am going to show how you can read multiple child nodes from Firebase Realtime Database.

To read multiple children; we first need to create them. I run this loop to create multiple children with User class objects and to differentiate, I added value of “i” (loop iteration variable) at the end of each value of the User class object.

Running this code will create a database like this in realtime database:

Realtime Database with multiple child nodes screenshots
Realtime Database with multiple child nodes screenshots

Now, the process of reading one node or multiple is pretty much the same. I will call addValueEventListener() to the reference object of the root node. This will provide me with a DataSnapshot; now this dataSnaphot object contains all the child nodes. I will call getChildren() method to get each child starting from the first one, I put it in an enhanced for loop and get all child one by one. Like this:

This is how you can read data from multiple child nodes. Now the next topic is how to Delete Data from Firebase Realtime Database

  • Deleting Data from Firebase Realtime Database

At one point or another, you must need to delete a certain node or value from your realtime database. Here is how you can do that:

Again, performing any option you need a reference, and a simple function named removeValue() to remove that node regardless of size of the node. It will be deleted if it contains any mode descendent node; all of those will be deleted as well.

I am going to delete the User0 from the database that we previously created using a loop. Here is the code snippet

The removeValue() function also returns a Task class object on which you can call the listeners to check either the delete was successful or not.

What is Firebase Cloud FireStore?

Like Firebase Realtime Database, it is also a NoSQL database, but unlike Realtime Database; it uses the Document Collection model to store data, not JSON.

It is flexible and scalable data available for iOS, Android, Web, Java, Node, and even Go language. Cloud Firestore is a little bit more organized by Firebase Realtime Database as it uses documents and collections.

Difference between Firebase Realtime Database and Firebase Cloud FireStore

Some people actually think that the old database (Realtime Database) is actually broken or outdated; that is why they made a new database model.

Well, that is not the case.

If you are using Firebase Realtime Database for your app you can continue doing that, it will work totally fine and they got no plane of removing it from Firebase Console.

Here are a few differences between the Firebase Realtime Database and Firebase Cloud Firestore:

Firebase Realtime Database

Firebase Cloud Firestore

Old Database model provided by Firebase

New Database model provided by Firebase

Uses JSON Tree to save data

Uses document collection model to save data

When a retrieve some element, you automatically get everything below it

Queries are shallow by default. If you fetch a document, within a collection, you only get that document.

Harder to manage when scale-up

Easier than Realtime Database to manage when grows up

What is the Document Collection Model?

You can think of documents as JSON objects which contain key-value pairs to store pretty much everything. These key-value pairs are called Fields.

Where the collection is basically, a collection of documents.

There are 4 rules of this model:

  1. As I said, the collection is a collection of documents, I mean it. Collection in Firestore can only contain documents; nothing else.
  2. Documents in Firestore can not be more than 1MB in size; you have to break it apart if it grows.
  3. A document can not contain other documents, can contain sub-collections and those sub-collections can contain documents, but no document can directly be saved into a document.
  4. The root of the Firestore can only contain collections. So if you just need to save “Hello world”, you need to create a collection first, then a document and then write a value to that document.

This is how a document collection model works, it can go really deep like a collection contains a document containing another collection and so on.

So you may need to save a path; which will also be referring to document->collection->document->collection.

Small Talk About Firebase Firestore Rules:

There are some rules for Firebase Firestore as well that describes which can and can not access which document.

You can visit the rules tab, and define your rules

Firestore Rules Tab
Firestore rules tab screenshot
  • Let anyone access anything

And here is the code that is generous; allowing anyone to read and write to Firestore Database. It may look scary at the start but not when I explain it to you.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
      match /{document=**}{
          // Any request for anything will be accepted
          allow read,write;
      }
  }
}

All Cloud Firestore Security Rules consist of the match statements, which identify documents in your database and allow expressions, which control access to those documents.

In the above code, the {docuemnt=**} is a wildcard that will match the rest of the path and write it into this variable document.

Which rest of the path, then one user requested.

Now that whatever path user try to access the rule inside those curly braces will be applied. Which says, all read, write; So anyone can access any document/collection.

This is for testing/demonstration purposes, never roll out to the production with these rules.

  • Let anyone access one document only

I created a collection named “col1” in Firestore from Firebase Console, added a document named “doc1” to that collection and placed some random values to it. Here is how it looks like:

Firestore Screenshot
Firestore Screenshot

Now I want anyone to access this document only, nothing else.

Here is how I do that:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
          //Setting condition to col1 documents
      match /col1/{document}{
          //Checking if the requested document is doc1, then let read write
           allow read,write : if document=="doc1";
      }
      match /{document=**}{
          // anything else read/write requested will be rejected
          allow read,write : if false;
      }
  }
}

As you can see I added a new match statement that will check if request document is doc1 in col1 or not, if yes then request will be granted; even though the request is being rejected in the next match statement but they work in sequence.

If a request is granted in the first place, then it will be considered granted even when rejected at someplace below.

You might also note that I used another wildcard here {document} which stores the id of single path element either document or collection and stick it to the name “document”. That’s all that it does.

  • Letting Signed Users In

That is a usual case and much needed that you want only signed-in users to access the data otherwise just show them signup page at the client-side.

To perform a sign-in check, we can use request.auth value. Here is how:

So I am continuing with the last example, but here I am checking if the requested document is doc1 and the user is signed in or not.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
          //Setting condition to col1 documents
      match /col1/{document}{
          //Checking if the requested document is doc1, then let read write
           allow read,write : if document=="doc1" && request.auth!=null;
      }
      match /{document=**}{
          // anything else read/write requested will be rejected
          allow read,write : if false;
      }
  }
}

Now, I just added another condition to our existing if statement which checks if the user is signed in or not. There are other a lot of interesting conditions like:

Letting user having Gmail account only; so we will perform the check as:

if request.auth.toked.email.matches('.*google[.]com$')

You can make the rule as you want. I would highly recommend you to go check out this video to understand mode about rules.

Surprise: you don’t need to run an Android Application to test the rule.

Firebase provided a simulator right in Firebase console that you can use to check if the rules you wrote are working as expected or not.

Adding Firebase Firestore into your Android App

Before adding Firebase Firestore to your Android project, make sure your project is connected to Firebase.

Open the Firebase Assitant pane in Android Studio, search for Firestore (found at the bottom in my case) and expand that.

You will see a button/hyperlink as “Read and write documents with Cloud Firestore” click that

Adding Firestore to Android
Adding Firestore to Android Studio using the plugin

The first option you see is of course “Connect your app to Firebase“, you must do that.

The second option is “Add Cloud Firestore to your app” with a button for it. Just click that.

Adding Firestore
Adding Firestore

You will see a new dialogue, showing you the changes that will be made. Hit “Accept Changes” button.

Implementing libraries for Firestore
Implementing libraries for Firestore android studio

Android Studio will implement those changes and sync the project for you. Once completed, the Firebase Cloud Firstore code will be available there. You can perform the read-write operation now.

Writing to Firebase Firestore

Like the Firebase Realtime Database, you also need an instance of the database. And getting that is almost same as the Realtime Database, look:

//Getting Database Instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();

Now that you got an instance, you can start creating documents and collections and start writing data.

Creating a Collection in Firestore

If you go to Firestore in Firebase Console and try to create a collection, you will see that it will ask you for a document as well (check below screenshot).

It is because you can not create an empty collection; not through Firebase console nor through Android Studio.

Creating a collection in Firestore
Creating a collection through Firestore

If you run the following code to get a reference to a collection that does not exist and you expect that it will be created, sorry for the disappointment.

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting reference of collection
        CollectionReference ref = db.collection("users");

You will never get to create an empty collection, besides what is the point of creating just a collection. You need to put a document in that.

Creating a Document in Firestore

In the above screenshot, if you noticed carefully, it is asking for a field with value as well.

It means you can not create an empty document either.

Another disappointment -_- but again what’s the point of creating an empty document?

Creating a document in Firestore
Creating a document in Firestore using Firebase Console

You need to put at least a field with some value in order to create a collection and a document.

Storing Single String in Firestore Document

That is what Firebase wants to do, write something, DO NOT create empty things.

Here is how you can save a field “username” and assign “waqas” to it. Only then you will be allowed to create a document and a collection.

Here is how you can create a document and put a single string there.

REMEMBER: if a collection exists at the same level and has the same name then no new collection will be created but this “new doc” will be added to that existing collection.

But if the same is the case with the document, the old document will be replaced, so be careful.

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();

        //Creating Map for the values we want to store
        Map<String ,String> data = new HashMap<>();
        data.put("username","waqas");

        //Getting Reference to "users" collection
        //REMEMBER: at this point, no collection will be created
        CollectionReference collectionReference = db.collection("users");

        //Getting reference to "new doc" document
        //REMEMBER: at this point, no document will be created either
        DocumentReference documentReference = collectionReference.document("new doc");

        //Writing data
        //REMEMBER: here both collection and document will be created and fields and values we created in hash will be stored to that document.
        documentReference.set(data);

This code will create a collection with the name “users” to the root directory of the Firestore. That users collection will create a document named “new doc”.

That document will contain a field named “username” which contains value “waqas”. This is how you store a single string.

Here is how it looks like in Firestore:

Writing string to firestore
Writing String to Firestore

Similarly, you can add as many fields and values as you want.

Writing Data Directly to Firestore Collection

Nope, you can not write data directly to a collection because the collection can only contain the document.

But Firebase provides some methods that seem like you are writing data directly to a collection.

You can call add() function directly to a collection reference and pass the data/object/instance.

It may seem like writing to a collection but what Firebase does is, it creates a document with an auto-generated name and puts your data in that document.

Here is the code for that:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();

        //Creating Map for the values we want to store
        Map<String, String> data = new HashMap<>();
        data.put("username", "waqas");

        //Getting Reference to "users" collection and adding the data
        db.collection("users").add(data);

And this is how it will look like in Firebase Firestore:

Writing data directly to collection in firestore
Writing data directly to Firestore Collection

Amazed by that strange string in the document section? That is an auto-generated name for the document by Firebase.

Writing Some Complex Data to Firestore Document

We can not fully rely on a single string or a bunch of key-value pairs. We defiantly, at some point, need to write our model class directly to our database.

Sometimes these model classes can contain instances of other model class and things can get a little complex.

I am going to write the same “user” class that we created above while learning the Firebase Realtime Database.

The User Class:

package com.androidbull.myapplication;

public class User {
    String userName;
    String firstName;
    String lastName;
    Date dob;

    public User() {
    }

    public User(String userName, String firstName, String lastName, String day, String month, String year) {
        this.userName = userName;
        this.firstName = firstName;
        this.lastName = lastName;
        dob = new Date(day,month,year);
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Date getDob() {
        return dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }
}

The Date Class:

package com.androidbull.myapplication;

public class Date {
    String day,month,year;

    public Date() {
    }

    public Date(String day, String month, String year) {
        this.day = day;
        this.month = month;
        this.year = year;
    }

    public String getDay() {
        return day;
    }

    public void setDay(String day) {
        this.day = day;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }
}

Writing the User Class object is simple, create the object, initialise it and just pass it to set() function.

Here is how:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();

        //Creating and initializing User object
        User user = new User("user1234","waqas","younis","first","january","1990");

        //Getting Reference to "users" collection
        CollectionReference collectionReference = db.collection("users");

        //Getting reference to "new doc" document
        DocumentReference documentReference = collectionReference.document("new doc");

        //Writing data
        documentReference.set(user);

That’s it, quite simple and elegant. Here is how it will look like in Firestore:

Writing a custom object to Firestore
Writing a custom object to Firestore

It created a map inside that document and set the values to the field name according to the date class. It’s quite straight forward, isn’t it?

Firestore Callback Functions

You can not just push the data and expect it to be stored in Firestore.

There could be multiple cases when data is lost. We can not leave this loophole; it is catastrophic. Firebase Firestore Developers already knew and provided a clean way to handle it; they provided what we call “callback functions”

All functions that are meant to perform the write operations return an instance of  Task class. The Task class provides many abstract functions that can call to keep ourselves updated with results of operation.

Here is the code that creates a toast message if the operation went successful and a log report if something went wrong:

//Writing data and using call-back functions
documentReference.set(user).addOnCompleteListener(new OnCompleteListener<Void>() {
    @Override
    public void onComplete(@NonNull Task<Void> task) {
        if (task.isSuccessful()) {
            //Tas was successful
            Toast.makeText(MainActivity.this, "User Added", Toast.LENGTH_SHORT).show();
        }else{
            //Something went wrong
            Log.e(TAG, "onComplete: Error: " + task.getException().getLocalizedMessage() );
            
        }
    }
});

In this way, you can check what thing was opposing the write operation, it could be some internet problem, or the user got no permission to perform that operation or something else. But the error message will surely help you out to debug it.

Reading from Firestore

Now comes the counterpart, retrieving data from Firebase. Trust me, it is quite simple and we will cover it step by step

Reading a Document from Firestore

The first thing is, as usual, the reference of the file. You can create the reference by the previous method -the provided name of the collection and then document and so on.

Once you have the reference, you can simply call the get() method and let Firebase SDK do it work.

I am going to read the username value from the following Firestore database

Writing string to firestore
Reading String from Firestore

I need a reference to the “new doc” document contained in the “users” collection; I hope by now you should know how to get a reference to any document/collection in Firestore. Once, we have the reference; we can call the get method and fetch the value.

Here is code for that:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting Reference to "new doc" document
        //You can get the path in this way too, lot easier!
        DocumentReference documentReference = db.collection("users").document("new doc");


        //Calling the get() method with a callback function
        documentReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
            @Override
            public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                //Checking request result
                if (task.isSuccessful()) {
                    //Request was successful but it never means that data is found
                    DocumentSnapshot data = task.getResult();
                    if (data.exists()) {
                        //document named "new doc" found

                        //We know in which format we have writen data to that document, so we will get it in same manner
                        //We used map to store that value, now we will get that
                        Map<String, Object> map = data.getData();

                        //We know the value "waqas" was stored against key "username"
                        String username = (String) map.get("username");

                        Toast.makeText(MainActivity.this, "username: " + username, Toast.LENGTH_SHORT).show();


                    } else {
                        //document with name "new doc" not found at the path specified.
                    }

                } else {
                    //Request was not successful
                    //Could be some rules or internet problem
                    Log.i(TAG, "onComplete: Request unsuccessful, error: " + task.getException().getLocalizedMessage());
                }
            }
        });

It seems like a lot, but if you write code, you will know how easy it is.

Remember if you fetch a document that contains a collection, then you will not get that collection. That’s a difference between Firestore and Realtime Database.

Reading a Custom Object from Firestore

As there is a method to write a custom object to Firebase, there must be some method to read that. Well, lucky you. There is one and quite similar to the above method.

Just get the reference to that object and call the get() methods. That’s it ?.

I am going to read the following User class instance that we write while learning how to write. Now is the time to reverse that action.

Writing a custom object to Firestore
Reading a custom object from Firestore

Here is the code to do that:

//Getting instance
FirebaseFirestore db = FirebaseFirestore.getInstance();


//Getting Reference to "new doc" document
//You can get the path in this way too, lot easier!
final DocumentReference documentReference = db.collection("users").document("new doc");


//Calling the get() method with a callback function
documentReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
    @Override
    public void onComplete(@NonNull Task<DocumentSnapshot> task) {
        //Checking request result
        if (task.isSuccessful()) {
            //Request was successful but it never means that data is found
            DocumentSnapshot data = task.getResult();
            if (data.exists()) {
                //document named "new doc" found

                //We know in which format we have writen data to that document, so we will get it in same manner
                //We used map to store that value, now we will get that
                User user = data.toObject(User.class);

               String userName = user.getUserName();
               String lastName = user.getLastName();

                Toast.makeText(MainActivity.this, "username: " + userName, Toast.LENGTH_SHORT).show();


            } else {
                //document with name "new doc" not found at the path specified.
            }

        } else {
            //Request was not successful
            //Could be some rules or internet problem
            Log.i(TAG, "onComplete: Request unsuccessful, error: " + task.getException().getLocalizedMessage());
        }
    }
});

Getting All Documents from a Collection

There could be situations when you need to get all the documents in a specified collection. Firebase provided a solution for such a situation as well, all you need to execute that get() method directly to the collection reference whom documents you want to get.

Here is how:

 //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting Reference to "users" collection
        final CollectionReference collectionReference = db.collection("users");


        //Calling the get() method with a callback function
        collectionReference.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                if (task.isSuccessful()) {
                    //Task is successful
                    //Running enhanced for loop to get each document
                    for (QueryDocumentSnapshot documentSnapshot: task.getResult()){
                        //Printing data of each document to log
                        Log.i(TAG, "onComplete: query data: " + documentSnapshot.getData());
                    }
                }else{
                    //Task was not successful
                    Log.e(TAG, "onComplete: ERROR: " + task.getException().getLocalizedMessage() );
                }
            }
        });

There are many other kinds of operations that you can perform on the Firestore database to get exactly what you need.

Getting Realtime Updates in Firestore

Remember all the read methods we discussed above will provide you data for once only; and that only when you call those functions. They will not update you if data is changed like Realtime Database. There is a separate mechanism if you want to listen to updates.

You need a reference of a document whom updates you want to listen, and then call addSnapshotListener() to that reference. Here is how:

//Getting reference
final DocumentReference docRef = db.collection("users").document("new doc");


docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
    @Override
    public void onEvent(@Nullable DocumentSnapshot snapshot,
                        @Nullable FirebaseFirestoreException e) {
        //This method will be called for the first time when executed and 
        //everytime data is updated in Firebase Firestore by anyone
        
        //Check if there is any expection
        if (e != null) {
            //Somthing went wrong, printing the error message to log
            Log.w(TAG, "Listen failed.", e);
            return;
        }
        //There is no error
        
        //Checking is snapshop is not null and exists
        if (snapshot != null && snapshot.exists()) {
            //Logging data to log
            Log.d(TAG, "Current data: " + snapshot.getData());
            
        } else {
            Log.d(TAG, "Current data: null");
        }
    }
});

That’s it; now your Firestore got the power to update in realtime.

Deletion in Firestore

Deleting a document or collection is a kinda similar process as other Firestore processes. But they are much trickier than delete in Realtime Database as in Firestore if you delete a document containing a subcollection then that subcollection will not be deleted. Only the fields and their values will be deleted.

And if you delete the only document in a collection/subcollection, that collection will become empty and will not appear once you refresh the Firebase Console. Because empty collection can not exist in Firestore.

These things make it a little tricker than Realtime Database, but don’t worry; I will explain each and everything to you.

Let’s start with deleting a single field from a document in Firestore.

Deleting a Field from a Document in Firestore

You can delete a specific field in a specific document in a specific collection.

Here is how – it seems like Firebase is fooling the update() function to perform delete ?, anyway:

DocumentReference docRef = db.collection("cities").document("BJ");

// Remove the 'capital' field from the document
Map<String,Object> updates = new HashMap<>();
updates.put("capital", FieldValue.delete());

docRef.update(updates)

And that “capital” field in “BJ” document will be deleted. You can add callback functions to get an update regarding the result of the delete operation.

Deleting a document from Firestore

Just get the reference and call delete() function, that’s it.

Here is how:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting Reference to "users" collection
        final DocumentReference docRef = db.collection("users").document("new doc");


        //Deleting document named "new doc"
        docRef.delete();

That’s it. The “new doc” document will be deleted from Firestore. You can also use a callback method to determine if the delete was successful or not.

Here is how:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting Reference to "users" collection
        final DocumentReference docRef = db.collection("users").document("new doc");


        //Deleting document named "new doc"
        docRef.delete().addOnCompleteListener(new OnCompleteListener<Void>() {
            @Override
            public void onComplete(@NonNull Task<Void> task) {
                if(task.isSuccessful()){
                    //File Deleted
                }else{
                    //Something went wrong, logging the error message
                    Log.e(TAG, "onComplete: Error: " + task.getException().getLocalizedMessage() );       
                }
            }
        });

Now you are aware when the deletion process ends and when it’s successful or not; you can keep the user engaged now.

Deleting a collection from Firestore

Deleting a complete collection from a resource-limited app is not recommended by Firebase Team because it has negative security and performance implications. And there is no way to delete a collection for Android Device directly.

However, you can do that using Firebase Cloud Functions. But we know that if a collection is empty, it is kinda deleted as well because the empty collection can not survive. So we can start deleting all documents in a collection until it is empty.

But to do that we need the reference for each and every document in that collection, and we already learned how to do that.

As soon as we get the reference of the first document, we perform the delete operation to the first document. Repeat till there is no more document.

Here is how:

        //Getting instance
        FirebaseFirestore db = FirebaseFirestore.getInstance();


        //Getting Reference to "users" collection, calling get to retrieve data, adding a callback
        db.collection("users").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
            @Override
            public void onComplete(@NonNull Task<QuerySnapshot> task) {
                // Task complete
                if (task.isSuccessful()) {
                    //Task successful
                    //Getting each document one by one in that collection
                    for (QueryDocumentSnapshot documentSnapshot: task.getResult()){
                        //Performing the delete operation 
                        documentSnapshot.getReference().delete();
                    }
                }

            }
        });

And we managed to delete a complete collection?

But this is good for the situation where there are few documents in Firestore, if there are a ton of collection, you could run out-of-memory errors, and then you have to delete files in smaller batches.

Ask any questions in the comment section below, our experts will be happy to help you at no extra cost.

Author

Hi there! I am Founder at FirebaseTutorials and AndroidBull. My skills include Android App Development. If you have any idea that you would want me to develop? Let’s talk: [email protected]