20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Cloud Firestore のリアルタイムアップデートで初期状態の added イベント発火による課金を回避する

Last updated at Posted at 2019-11-10

はじめに

  • Firebase の Cloud Firestore をある程度触ってる方向けの内容なので、基礎的な説明は省きます。
  • サンプルコードは JavaScript ですので、他言語の SDK をお使いの方は適宜読み替えてください。

公式ドキュメントにも載っておらず、ググってもなかなか出てこない情報だったのでどなたかの役に立てば幸いです :pray:

何を解決したいか

ref. https://firebase.google.com/docs/firestore/query-data/listen

Cloud Firestore でリアルタイムアップデートを入手する際、以下のように何も考えず今までのドキュメントを全件取得すると、保存済みのデータ 1 件ごとに added イベントが発火します。

// チャットアプリなどで messages コレクションのドキュメントスナップショットを取得する例
firebase
  .firestore()
  .collection("messages")
  .orderBy("createdAt", "desc")
  .onSnapshot(snapshot => {
    snapshot.docChanges().forEach(change => {
      if (change.type === "added") {
        // 保存済みのデータ n 件分出力される
        console.log("New message:", change.doc.data());
      }
    });
  });

ref. https://firebase.google.com/docs/firestore/query-data/listen#view_changes_between_snapshots

最初のクエリ スナップショットには、クエリに一致する既存のすべてのドキュメントの added イベントが含まれています。これは、クエリの初期状態に対してクエリ スナップショットが最新の状態になるように、一連の変更を取得しているためです。

これの何が問題かというと、 added イベント 1 回につき 1 回の読み取りとしてカウントされてしまうので、ものすごく無駄なコストがかかってしまいます。

ref. https://firebase.google.com/docs/firestore/pricing#listens

クエリの結果をリッスンする場合、結果セット内のドキュメントを追加または更新するたびに、1 回の読み取りとして課金されます。

解決方法

上記のチャットアプリの例であれば、スナップショットとして以前の最新メッセージの保存時間より新しいメッセージだけ取得するようにすれば良いです。

※ Firestore の Timestamp 型と JavaScript の Date 型を比較するためには fromDate() メソッドを使って型変換してあげる必要があります。

// チャットアプリなどで messages コレクションのドキュメントスナップショットを取得する例
firebase
  .firestore()
  .collection("messages")
  .orderBy("createdAt", "desc")
  .where(
    "createdAt",
    ">",
    // 変数 lastCreatedAt には Date 型の値を渡してあげてください
    // See. https://firebase.google.com/docs/reference/js/firebase.firestore.Timestamp.html#fromdate
    firebase.firestore.Timestamp.fromDate(lastCreatedAt)
  )
  .onSnapshot(snapshot => {
    snapshot.docChanges().forEach(change => {
      if (change.type === "added") {
        // 新しく追加されたデータのみ出力される
        console.log("New message:", change.doc.data());
      }
    });
  });

参考

20
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?