Cloud Firestore + Android is just

    Not so long ago, Google launched Cloud Firestore. Cloud Firestore is a cloud-based NoSQL database that Google positions as a replacement for the Realtime Database. In this article I want to tell how to start using it.


    Opportunities


    Cloud Firestore allows you to store data on a remote server, easily access it and monitor changes in real time. The documentation has an excellent comparison of Cloud Firestore and Realtime Database.


    Creating and connecting to a project


    In the Firebase console, select Database and click on Create database. Next, select the access settings. For familiarization, a test mode will be enough for us, but on prod it is better to approach this issue more seriously. Read more about access modes here .



    To configure the project, perform the following steps:


    1. Add Firebase to the project according to the instructions from here.
    2. Add dependency to app / build.gradle
      implementation 'com.google.firebase:firebase-firestore:18.1.0'

    Now everything is ready.


    To get acquainted with the basic techniques of working with Cloud Firestore, I wrote a simple application . To work, you need to create a project in the Firebase console and add the google-services.json file to the project in Android Studio.


    Data storage structure


    Firestore uses collections and documents to store data. A document is a record that contains any fields. Documents are combined into collections. A document may also contain nested collections, but this is not supported on android. If we draw an analogy with the SQL database, then the collection is a table, and the document is an entry in this table. One collection may contain documents with a different set of fields.


    Receiving and recording data


    In order to get all the documents of a collection, the following code is enough


    remoteDB.collection(“Tasks”)
           .get()
           .addOnSuccessListener { querySnapshot ->
               // Успешно получили данные. Список в querySnapshot.documents
           }
           .addOnFailureListener { exception -> 
               // Произошла ошибка при получении данных
           }
    }

    Here we request all the documents from the Tasks collection .


    The library allows you to generate queries with parameters. The following code shows how to get documents from the collection by condition


    remoteDB.collection(“Tasks”)
           .whereEqualTo("title", "Task1")
           .get()
           .addOnSuccessListener { querySnapshot ->
               // Успешно получили данные. Список в querySnapshot.documents
           }
           .addOnFailureListener { exception -> 
               // Произошла ошибка при получении данных
           }
    }

    Here we request all documents from the Tasks collection for which the title field corresponds to the value of Task1 .


    Upon receipt of documents, they can be immediately converted to our data classes


    remoteDB.collection(“Tasks”)
           .get()
           .addOnSuccessListener { querySnapshot ->
               // Успешно получили данные. Список в querySnapshot.documents
              val taskList: List = querySnapshot.toObjects(RemoteTask::class.java)
           }
           .addOnFailureListener { exception -> 
               // Произошла ошибка при получении данных
           }
    }

    To write, you need to create a Hashmap with data (where the name of the field acts as the key, and the value of this field as the value) and transfer it to the library. The following code demonstrates this


    val taskData = HashMap()
    taskData["title"] = task.title
    taskData["created"] = Timestamp(task.created.time / 1000, 0)
    remoteDB.collection("Tasks")
        .add(taskData)
        .addOnSuccessListener {
            // Успешная запись
        }
        .addOnFailureListener {
            // Произошла ошибка при записи
        }

    In this example, a new document will be created and Firestore will generate an id for it. To set your own id do the following


    val taskData = HashMap()
    taskData["title"] = task.title
    taskData["created"] = Timestamp(task.created.time / 1000, 0)
    remoteDB.collection("Tasks")
        .document("New task")
        .set(taskData)
        .addOnSuccessListener {
            // Успешная запись
        }
        .addOnFailureListener {
            // Произошла ошибка при записи
        }

    In this case, if there is no document with id equal to New task , then it will be created, and if there is, then the specified fields will be updated.


    Another option for creating / updating a document


    remoteDB.collection("Tasks")
        .document("New task")
        .set(mapToRemoteTask(task))
        .addOnSuccessListener {
            // Успешная запись
        }
        .addOnFailureListener {
            // Произошла ошибка при записи
        }

    Subscribe to changes


    Firestore allows you to subscribe to data changes. You can subscribe to changes to the collection as well as changes to a specific document


    remoteDB.collection("Tasks")
            .addSnapshotListener { querySnapshot, error ->
                // querySnapshot - список изменений
                // error - ошибка 
            }

    querySnapshot.documents - contains an updated list of all documents
    querySnapshot.documentChanges - contains a list of changes. Each object contains a modified document and type of change. 3 types of changes are possible
    ADDED - the document is added,
    MODIFIED - the document is changed,
    REMOVED - the document is deleted


    Loading large amounts of data


    Realtime Database provides a less convenient mechanism for downloading large amounts of data, which consists in manually editing the json file and downloading it. Out of the box, Firestore provides nothing of the kind. It was very inconvenient to add new documents until I found a way to easily load a large amount of information. So that you do not have such problems as mine, below I will attach instructions on how to quickly and easily download a large amount of data. The instruction was found on the Internet.


    1. Install Node.js and npm
    2. Install the firebase-admin package by running the command
      npm install firebase-admin --save
    3. Generate json file with collection data. An example can be found in the Tasks.json file .
    4. To download, we need an access key. How to get it is well described in this article.
    5. In the file export.js put down your data
      require ('./ firestore_key.json') - a file with an access key. I was in a folder with a script
      - the name of your firestore database is
      "./json/Tasks.json" - the path to the file in which the data is located
      ['created'] - a list of field names with the type Timestamp
    6. Run the script
      node export.js
      The script uses the dalenguyen best practices

    Conclusion


    I used Cloud Firestore in one of my projects and did not experience any serious problems. One of my collections contains about 15,000 documents and queries on it are pretty fast and this is without the use of indexes. Using Cloud Firestore in conjunction with Room and Remote Config, you can significantly reduce the number of calls to the database and not go beyond free limits. At a free tariff per day, you can read 50,000 documents, record 20,000 and delete 20,000.


    Application performance


    Also popular now: