12
4

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 3 years have passed since last update.

Firestoreの複合インデックスでつまったところまとめ

Posted at

対象読者

複合インデックスを登録しているのに取得できない方

解決方法

まず、エラー内容を確認します。firebase Functionsを使っている方はfirebaseのコンソールに入って、Functionsのログからエラーを確認してください。もし使われていない方は、例外処理によってエラー内容を返して確認してみてください。以下のエラー(一部抜粋)が出力されていると思います。

"details": "The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/[projectID]/firestore/indexes?create_composite=[文字列]",

「クエリを実行するにはインデックスが必要なので作ってくださいね」と書かれており、親切にURLも記載してくれています:clap:。アクセスすると、Google Cloud PlatFormがブラウザで開き、インデックスを登録するかを聞かれますので、そのままインデックスを登録をしてください。
登録が成功された状態でAPIを実行すると、無事にデータが取得できるようになります。(この解決方法は公式ドキュメントにも記載されています。)

実際につまったところと原因

以下のような構造をとったデータが保存されているとします。

interface
interface Log {
  user_id: string
  message_id: string
  created_at: string
}

そのデータを以下の条件で取得したいと仮定します。
①あるユーザーのログをメッセージごとに並び替え、さらに作成日の順に並び替えて取得する
②あるメッセージのログをユーザーごとに並び替え、さらに作成日の順に並び替えて取得する

model/index.js
// ①の場合のクエリ
snapshot = await docRef
    .where('user_id', '==', userId)
    .orderBy('message_id')
    .orderBy('created_at')
    .get()

// ②の場合のクエリ
snapshot = await docRef
    .where('message_id', '==', messageId)
    .orderBy('user_id')
    .orderBy('created_at')
    .get()

このクエリに対し、以下のインデックスを事前に登録していました。

コレクションID インデックス登録されるフィールド クエリのスコープ
collection_id user_id 昇順 message_id 昇順 created_at 昇順 コレクション

※表の列の名前は、それぞれfirebaseのコンソールでFirestoreにアクセスし、インデックスに書かれているものです。Google Cloud PlatFormで見た場合は
  インデックス登録されるフィールド → フィールド
  クエリのスコープ → Query scope
となっています。

この状態で実際にAPIを実行すると、①は取得できて②ではエラーになります。
そして、上記の解決方法に記載の通りクエリを作成すると、インデックスが以下のようになります。

コレクションID インデックス登録されるフィールド クエリのスコープ
collection_id user_id 昇順 message_id 昇順 created_at 昇順 コレクション
collection_id message_id 昇順 user_id 昇順 created_at 昇順 コレクション

ここで、もう一度APIを実行すると先ほどエラーだった②も取得できるようになります。
つまり、原因はクエリで指定している複数のインデックスをその順にインデックスに登録していなかったこととなります。今回のケースでは、使用したフィールドは同じでしたが、厳密には条件が異なっており、インデックスも別々に定義する必要があったようです。

このように条件が違えばインデックスを新たに定義すればいいと言うことが分かったのですが、やみくもにインデックスを作成していると利用料金(インデックスはストレージの料金として計上されるみたいです)が無駄にかかってしまうので、インデックス マージを活用して重複するインデックスを削減する、と言ったことも可能みたいです。


公式ドキュメントを読んでみて「複合インデックスを登録すると複数のフィールドを組み合わせたインデックスを作成でき、それによってデータが取得できるようになる」と自分なりに解釈をしてみたのですが、組み合わせであっても順番を担保しないといけないのは何故なのでしょうか、、詳しい方いらっしゃいましたら教えていただきたいです、、:pray:

12
4
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
12
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?