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

Для настройки проекта проделываем следующие шаги:
- Добавить Firebase к проекту по инструкции от сюда
- Добавить зависимость в 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 из коробки ничего такого не предоставляет. Было очень неудобно добавлять новые документы, пока я не нашел способ как можно легко загрузить большой объем информации. Чтобы у вас не было таких проблем как у меня, ниже приложу инструкцию как быстро и легко загрузить большой объем данных. Инструкция была найдена на просторах интернета.
- Установить Node.js и npm
- Установить пакет firebase-admin выполнив команду
npm install firebase-admin --save - Сформировать json-файл с данными коллекции. Пример можно посмотреть в файле Tasks.json
- Для загрузки нам понадобиться ключ доступа. Как его получить хорошо описано в этой статье
- В файле export.js проставить свои данные
require('./firestore_key.json') — файл с ключом доступа. У меня лежал в папке со скриптом
<YOU_DATABASE> — название вашей firestore-базы
"./json/Tasks.json" — путь до файла в котором лежат данные
['created'] — список имен полей с типом Timestamp - Выполнить скрипт
node export.js
В скрипте используются наработки dalenguyen
Заключение
Cloud Firestore я использовал в одном из своих проектов и не испытал никаких серьезных проблем. Одна из моих коллекций содержит около 15000 документов и запросы по ней проходят довольно быстро и это без использования индексов. Используя Cloud Firestore совместно с Room и Remote Config можно существенно сократить количество обращений к базе и не выходить за бесплатные лимиты. На бесплатном тарифе в день можно прочитать 50000 документов, записать 20000 и 20000 удалить.

