Как стать автором
Обновить

Cloud Firestore + Android это просто

Время на прочтение4 мин
Количество просмотров29K

Не так давно Google зарелизил Cloud Firestore. Cloud Firestore — это облачная NoSQL база данных, которую Google позиционирует как замену Realtime Database. В этой статье я хочу рассказать как начать ей пользоваться.


Возможности


Cloud Firestore позволяет хранить данные на удаленном сервере, легко получать к ним доступ и следить за изменениями в режиме реального времени. В документации есть отличное сравнение Cloud Firestore и Realtime Database.


Создание и подключение к проекту


В консоли Firebase выбираем Database и нажимаем на Create database. Дальше выбираем настройки доступа. Для ознакомления нам будет достаточно тестового режима, но на проде лучше подойти к этому вопросу серьезнее. Подробнее про режимы доступа можно почитать здесь.



Для настройки проекта проделываем следующие шаги:


  1. Добавить Firebase к проекту по инструкции от сюда
  2. Добавить зависимость в app/build.gradle
    implementation 'com.google.firebase:firebase-firestore:18.1.0'

Теперь все готово.


Для ознакомления с базовыми приемами работы с Cloud Firestore я написал простенькое приложение. Для его работы необходимо создать проект в консоли Firebase и добавить файлик google-services.json в проект в Android Studio.


Структура хранения данных


В Firestore для хранения данных используются коллекции и документы. Документ — это запись, которая содержит какие-либо поля. Документы объединяются в коллекции. Также документ может содержать вложенные коллекции, но на андроиде это не поддерживается. Если проводить аналогию с SQL-базой, то коллекция — это таблица, а документ — это запись в этой таблице. Одна коллекция может содержать документы с разным набором полей.


Получение и запись данных


Для того чтобы получить все документы какой-либо коллекции достаточно следующего кода


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

Здесь мы запрашиваем все документы из коллекции Tasks.


Библиотека позволяет формировать запросы с параметрами. Следующий код показывает как получить документы из коллекции по условию


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

Здесь мы запрашиваем все документы из коллекции Tasks, у которых поле title соответсвует значению Task1.


При получении документов, их можно сразу конвертировать в наши data-классы


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

Для записи необходимо сформировать Hashmap с данными (где в качестве ключа выступает название поля, а в качестве значения — значение этого поля) и передать библиотеке. Следующий код это демонстрирует


val taskData = HashMap<String, Any>()
taskData["title"] = task.title
taskData["created"] = Timestamp(task.created.time / 1000, 0)

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

В данном примере будет создан новый документ и Firestore сгенерирует ему id. Чтобы задать собственный id необходимо сделать следующее


val taskData = HashMap<String, Any>()
taskData["title"] = task.title
taskData["created"] = Timestamp(task.created.time / 1000, 0)

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

В этом случае если нет документа с id равном New task, то он будет создан, а если есть, то указанные поля будут обновлены.


Еще один вариант создания/обновления документа


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

Подписываемся на изменения


Firestore позволяет подписаться на изменения данных. Подписаться можно как на изменения коллекции, так и на изменения конкретного документа


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

querySnapshot.documents — содержит обновленный список всех документов
querySnapshot.documentChanges — содержит список изменений. Каждый объект содержит измененный документ и тип изменения. Возможны 3 типа изменений
ADDED — документ добавлен,
MODIFIED — документ изменен,
REMOVED — документ удален


Загрузка большого количества данных


Realtime Database предоставляет более менее удобный механизм загрузки большого количества данных, который заключается в ручном редактировании json-файла и его загрузки. Firestore из коробки ничего такого не предоставляет. Было очень неудобно добавлять новые документы, пока я не нашел способ как можно легко загрузить большой объем информации. Чтобы у вас не было таких проблем как у меня, ниже приложу инструкцию как быстро и легко загрузить большой объем данных. Инструкция была найдена на просторах интернета.


  1. Установить Node.js и npm
  2. Установить пакет firebase-admin выполнив команду
    npm install firebase-admin --save
  3. Сформировать json-файл с данными коллекции. Пример можно посмотреть в файле Tasks.json
  4. Для загрузки нам понадобиться ключ доступа. Как его получить хорошо описано в этой статье
  5. В файле export.js проставить свои данные
    require('./firestore_key.json') — файл с ключом доступа. У меня лежал в папке со скриптом
    <YOU_DATABASE> — название вашей firestore-базы
    "./json/Tasks.json" — путь до файла в котором лежат данные
    ['created'] — список имен полей с типом Timestamp
  6. Выполнить скрипт
    node export.js
    В скрипте используются наработки dalenguyen

Заключение


Cloud Firestore я использовал в одном из своих проектов и не испытал никаких серьезных проблем. Одна из моих коллекций содержит около 15000 документов и запросы по ней проходят довольно быстро и это без использования индексов. Используя Cloud Firestore совместно с Room и Remote Config можно существенно сократить количество обращений к базе и не выходить за бесплатные лимиты. На бесплатном тарифе в день можно прочитать 50000 документов, записать 20000 и 20000 удалить.


Гифка работы приложения

Теги:
Хабы:
Всего голосов 12: ↑11 и ↓1+10
Комментарии9

Публикации

Работа

Ближайшие события