TOP(About this memo)) > 一覧(Firestore) > リアルアップデート(リスナー)
Cloud Firestore でリアルタイム アップデート
- https://firebase.google.com/docs/firestore/query-data/listen?hl=ja
db.collection("cities").doc("SF").snapshots().listen 〜〜
db.collection("cities").where("state", isEqualTo: "CA").snapshots().listen〜〜
- スナップショット リスナーとも呼ばれる。
- コンテンツが変更されるたびに、別の呼び出しによってドキュメント スナップショットが更新。
- レイテンシ補正
- アプリでローカル書き込みが行われると、すぐにスナップショットリスナーが起動し、データがバックエンドに送信される前に、新しいデータがリスナーに通知される。
- metadata.hasPendingWrites プロパティを見ることで、バックエンドへ書き込み済かどうか分かる。
- なお、書き込みが完了したことだけを知りたい場合は、hasPendingWrites を使用する代わりに、完了コールバックをリッスンして確認すれば良い
- メタデータ変更のイベント
- デフォルトでは、メタデータにのみ影響する変更は、リスナーに通知されない。
- メタデータが変更されたときにスナップショット イベントを受け取る必要がある場合は、リスナーをアタッチするときに ListenOptions オブジェクトを渡す。
- 初期状態
- 初期状態は、サーバーから直接取得することも、ローカル キャッシュから取得することもできる。
- ローカルキャッシュに使用可能な状態がある場合、クエリ スナップショットにはキャッシュされたデータが最初に入力され、その後、クライアントがサーバーの状態に追いついたときにサーバーのデータで更新。
- listenのイベントに含まれるもの
- .docs
- .docChanges 変更内容の配列
.type
- 変更の種類(added、modified、removed)
- データベース上の変更ではなく、クエリーの結果に対する変更という点に注意。
- 最初のクエリスナップショットには、クエリに一致する既存のすべてのドキュメントの added イベントが含まれている。
.data()
差分ではなく対象データがすべて入っている
- デタッチ
- データをリッスンする必要がなくなったら、イベント コールバックが呼び出されないようにリスナーをデタッチできる。
listener.cancel();
- なお、リスナーのアタッチ時にエラーが発生した場合(コールバックにて確認)は、リスナーはそれ以上イベントを受信しなくなるため、リスナーのデタッチは不要
(応用)大規模なリアルタイムクエリ
- https://firebase.google.com/docs/firestore/real-time_queries_at_scale?hl=ja
- 実行されているアプリが Cloud Firestore への接続を確立すると、その接続は、データベースが配置されているのと同じリージョンにある Cloud Firestore フロントエンド サーバーにルーティングされる。
- ユーザーの物理的な場所と Cloud Firestore データベースの場所の間の距離は、ユーザーが経験するレイテンシに影響
- アーキテクチャ
- https://firebase.google.com/docs/firestore/real-time_queries_at_scale?hl=ja#understand_the_real-time_query_system
- Cloud Firestore への接続を開き、Firebase SDK を介してonSnapshot(collection(“chatroom”))を呼び出してリスナーを登録。
- このリスナーは、何時間もアクティブな状態を維持できる。
- Cloud Firestore フロントエンドは、基盤となるストレージ システムにクエリを実行してデータセットをブートストラップ。それをユーザーのデバイスに送信する。
- その後、リッスンモードに移行し、リスナーはサブスクリプション ハンドラーに登録し、データの更新を待つ。
- 状況によっては、リスナがリスニング状態からポーリング状態に戻ることもある。
- こちらは自動的に行われ、SDK とアプリに対して透過的
- データベースは、ドキュメントの変更をストレージ システムにコミットするとともに、同じ更新を内部変更ログにコミットする。
- 変更ログは、変更が発生したときに変更の厳密な順序を確立
- 変更ログは、更新されたデータをサブスクリプション ハンドラーのプールにファン アウト。そして、更新されたドキュメントが現在登録されているスナップショット リスナーと一致するかどうかマッチング処理が行われる。(Firebase セキュリティ ルールの評価もされる)
- Cloud Firestore のスケーラビリティの重要な部分は、変更ログからサブスクリプションハンドラおよびフロントエンド サーバーへのファンアウトに依存
- これらのコンポーネントの多数のレプリカを複数のゾーン (マルチリージョン デプロイの場合は複数のリージョン) で実行することにより、Cloud Firestore は高可用性とスケーラビリティを実現
- モバイルおよび Web SDK から発行されるすべての読み取り操作は、このモデルに従っている。
- リアルタイム リスナー、ドキュメントを取得するための呼び出し、およびワンショット クエリにも適用。
- 単一ドキュメントの取得とワンショット クエリは、パフォーマンスに関して同様の制約が伴う、有効期間が短いスナップショット リスナーと考えることができる。
- 多くのアプリは予測可能な有機的成長を遂げており、Cloud Firestore は予防措置なしで対応できる。ただし、大規模なデータセットのインポートなどのバッチ ワークロードでは、書き込みが急激に増加する可能性がある。
- Key Visualizer は、書き込みホットスポットを分析できる
- ユーザーがデータの変更をすばやく確認できるようにするには、ドキュメントと書き込み操作を小さく保つようにする。
- 小さなドキュメントと書き込み操作は処理が高速で、アプリの応答性が向上。
- 数百のフィールドと大規模なデータを含む大規模なドキュメントは、処理に時間がかかる。
- リアルタイム クエリ システムは、書き込み操作と読み取り操作を接続するパイプラインと考えることができる。
- Cloud Firestore の変更ログ構造は強力な整合性を保証し、データベースへのコミットについて、アプリが順不同の更新の通知を受信することはない。
- 裏を返せば、書き込み操作が遅くなると、読み取り操作に悪影響を与える可能性があることを意味する。
- ホットスポットを回避することが、この問題を回避するための鍵
- 効率的なリスナーを使用する
- スナップショットリスナーと、ワンショット クエリ
- スナップショット リスナーは、最初のポーリング操作とそれに続くデータが実際に変更されたときの通知を読み取る。
- ワンショット クエリは、アプリが最後にクエリを実行してから変更されていない可能性があるデータを再読み取りする。
- 多くの場合、Cloud Firestore を使用するアプリを構築するには、リスナーを開いて可能な限り長く維持することが最も費用対効果の高い方法。
- アプリが大量のデータを消費する必要がある場合、スナップショット リスナーは適切ではない可能性がある。
- たとえば 1 秒間に多数のドキュメントを長時間プッシュする場合は、より低い頻度で実行されるワンショット クエリを選択する