[recovery mode] Личный опыт работы с Firebase Cloud Firestore
Всем привет! В последнее время все чаще использую Firebase в своих проектах: очень удобно обходится без фактического написания серверной части. Хочу поделиться небольшим опытом работы на стороне фронтенда. В данном случае это Angular, поэтому используется официальная библиотека AngularFire. Наперед отмечу, что в Android лучше обстоят дела с библиотеками и реализацией возможностей Firebase, как мне показалось.
Больше касаемо Firestore
Первое, это Offline Data. Она по умолчанию включена в Android и iOS, но для веба отключена, и это оказалось не удивительным. Мне абсолютно не понравилась эта возможность на сегодняшний день, так как данные не обновлялись (а должны были бы) даже после перезагрузки страницы, и нет никаких явных рычагов управления (по крайней мере, в документациях) для их очистки или обновления. Они хранятся в IndexedDB, их можно вручную очистить, однако firebase постоянно подключен к бд. Т.е. почти единственная возможность для пользователя удалить (== очистить в данном случае) только при начале загрузки страницы, когда firebase еще не инициализирован. Поэтому я решил проблему переходом по ссылке window.location.href += '?clear';
, затем после перезагрузки страницы в главном html файле выполнением такого первоочередного скрипта:
Работает, но не скажу, что решает главные проблемы, поскольку просто ужасно реализована синхронизация.
Во-вторых, не используйте valueChanges
у collection и document, поскольку в 99% случаев необходимы метаданные (оказывается). Хардкодно запоминать uid документа в каком-либо его поле; оптимальный способ будет использовать snapshotChanges
с map-ом для получения непосредственного uid, как здесь для Angular:
this.store.collection("yourCollection", ref => {
return ref.orderBy("yourFiled");
}).snapshotChanges()
.map(actions => {
return actions.map(action => {
return {
_uid: action.payload.doc.id,
...action.payload.doc.data()
};
});
})
Еще хотел бы отметить, что коллекции и документы независимы друг от друга, т.е. вы не получите при выборки документа его subcollections: это отдельные данные, и сделано это просто для удобства представления данных (одно из главных отличий от Realtime Database).
Здесь же при проектировании бд учитывайте ограничение на размер документа в 1 Мб. И если данных может быть много (какого-либо array), то надо выносить их в subcollection.
Больше касаемо Angular
Важный вопрос был о сохранении документа так, чтобы не перезаписывать другие поля. Собственно, нашел такое решение:
this.store.collection(collection)
.doc(document).ref
.set(object, {
merge: true
})
.then(() => this.showSnackbar("Изменения сохранены"))
.catch((error) => {
console.log(error);
this.showSnackbar("Не удалось сохранить изменения");
});
// замечу, что showSnackbar должен быть реализован как функциональный литерал
showSnackbar = (message) => {
this.snackbar.open(message, null, {
duration: 1000
});
};
Для экономии ресурсов Firebase (спасибо отличной реализации Offline Data) данные храню в буфере ReplaySubject
. Все бы хорошо, но невозможно очистить его при обновлении данных, поэтому приходится его пересоздавать:
clearDocuments() {
this._documents.complete();
this._documents = null;
this._documents = new ReplaySubject();
this._refresh.next(true);
}
Здесь _refresh это BehaviorSubject
, с ним отлично сочетается switchMap
:
this.service._refresh.asObservable()
.switchMap(() => {
this.items.data = [];
return this.service._documents.asObservable();
})
.subscribe(document => {
});
Небольшое личное впечатление
Я имел опыт работы с Realtime Database и скажу, что Firestore более продвинутое хранилище, хотя и возможно со своими недостатками. Даже в плане работы в консоли (бывало по ошибке удалял корневой узел Realtime Database)
В Firestore нет онлайн эмулятора правил (собственно тесты никто не отменял), поэтому для тестирования я использую библиотеку firestore-security-tests
. Она работает замечательно, единственно, вот такого типа выборки get(/databases/$(database)/documents/info/app).data.version
не поддерживаются.
Надеюсь, с релизом Firestore все изменится к лучшему
Дополнение
Никак только не получается подключить Firebase с правами админа для внутреннего сайта (а из-за этого приходится хардкодить с правилами, единственно хорошо, что в консоли можно указать подпись сертификата приложения и тп). Есть решение для Node.js, но как-то не удалось еще внедрить его. Может кто имеет такой опыт?