先にまとめ

  • たぶん先にウェブコンソールで編集 → 結果を JSON へ保存、という流れ
  • firebase firestore:indexes で「現在設定されているインデックス」をJSONで得られる
  • なので、書式は不明だけど気にする必要なさそう
  • エラーメッセージにインデックス作成 URL が含まれる(のでそれを使う)

ここまでのあらすじ

一覧を新しいもの順にしようと orderBy() 追加したらエラーになった。

const collRef = firebase.firestore().collection(collectionName)
  .where('userId', '==', userId)
  .orderBy('updatedAt', 'desc');
FirebaseError: The query requires an index. You can create it here: https://console.firebase.google.com/project/your-project/database/firestore/indexes?create_composite=…

このクエリーにはインデックスが必要だよ、この URL から作れるよ。とのこと。

インデックスを作成する

firestore.indexes.json が気になるところなんだけど、後回し。

エラーメッセージに含まれる URL を開くと Firestore の Indexes のページが出てきて、「インデックス作るよ!」というダイアログが表示される。

Create composite index というダイアログ。これから作成するインデックスの対象コレクション、フィールドと昇順、降順が確認できる。

素直に “Create index” ボタンを押せばすぐ作ってくれる。

いや、すぐは作ってくれない

すぐ作り始めてはくれるんだけど、なかなか時間がかかる様子。

更新が必要なデータ量によっては、インデックスの作成に数分かかる場合があります。

手元の 10 件ない程度の環境で、完了まで 30 秒くらいにかかった。

インデックスを firestore.indexes.json で管理する

後から環境を再現できるようリポジトリーに設定を持っておきたい。わかる。

firebase initfirestore.indexes.json というファイルを作ってくれるんだけど、どうやらこのJSONファイルをいじるのではなく、先にコンソールで作業してから記録するというのが良さそう。

つまりこんな流れ。

  1. ウェブのコンソールで作業(前節でやった)
  2. firebase で定義のスナップショットを firestore.indexes.json へ保存
  3. 必要に応じて firebase からデプロイして環境を再現

スナップショットを保存

スナップショットという表現で良いのかわかんないけども。

firebase コマンドで現在設定されているものをJSONで得られる。標準出力に出てくるので、> を使ってJSONファイルへ上書き出力してやる。

$ firebase firestore:indexes > firestore.indexes.json

結果、例えばこんな感じであるらしい。

{
  "indexes": [
    {
      "collectionGroup": "rooms",
      "queryScope": "COLLECTION",
      "fields": [
        {
          "fieldPath": "userId",
          "order": "ASCENDING"
        },
        {
          "fieldPath": "updatedAt",
          "order": "DESCENDING"
        }
      ]
    }
  ],
  "fieldOverrides": []
}

デプロイして環境再現

本番環境を更新するとか開発環境を作り直すとかは、JSON ファイルを用意したあとは普通にデプロイするだけ。インデックスだけの場合は --only firestore:indexes で。

$ firebase deploy --only firestore:indexes

最初間違えて単数 firestore:index とやってしまい、でもエラーにならないので気づくのに時間がかかった……。

なお JSON へ追加してデプロイすると作成してくれるけど、JSON で削除してデプロイしても実際に削除してくれない。 (追記 2021-02-13)確認して削除してくれるようになっていた。

i  deploying firestore
i  firestore: reading indexes from firestore.indexes.json...
i  firestore: The following indexes are defined in your project but are not present in your firestore indexes file:
        (rooms) -- (userId,ASCENDING) (updatedAt,DESCENDING)
? Would you like to delete these indexes? Selecting no will continue the rest of the deployment.
 Yes
i  firestore: Deleting 1 indexes...
✔  firestore: deployed indexes in firestore.indexes.json successfully

べんり!(追記おわり)

コマンド詳細

$ firebase firestore:indexes --help
Usage: firestore:indexes [options]

List indexes in your project's Cloud Firestore database.

Options:
  --pretty    Pretty print. When not specified the indexes are printed in the JSON specification format.
  -h, --help  output usage information

CI でデプロイするとしばらくエラーに

CI から firebase deploy するプロジェクトで試したところ、Firestore の更新も Hosting へのアップロードも同時に行われるため、Firestore のこのインデックス作成完了までの間はエラーになってしまった。なんか対応のしようがあるんだろうか? いったん firebase deploy --only firestore:indexes して、準備完了をどうにかして検知して、それから Hosting を更新するなんてことができる?

削除して再作成

削除はコンソールで Firestore → Indexes の一覧右側 “…” から。すぐ終わる。

終わるが、そのあとすぐに作り直そうとするとエラーになった。

$ firebase deploy --only firestore:indexes

=== Deploying to 'my-project'...

i  deploying firestore
i  firestore: reading indexes from firestore.indexes.json...

Error: HTTP Error: 409, index already exists

たぶんサーバー側の中のどこかでキャッシュみたいなものが残ってるんではなかろうか。知らんけど。

3 分程度間をおいて再実行したら成功した。作成と同様、量によって時間が伸びると思う。

セキュリティルールは先に JSON を書く

じゃあインデックスだけじゃなくてセキュリティルールも先にコンソールでやるのか、と思ったけどどうもそうでもないらしい。

firebase --help で出てくるコマンド一覧には、Firestore 関連のものはこの indexesdelete のふたつだけ。やっぱりコンソールで試して → JSON コピペして保存して → デプロイ、という流れか。

おしまい

参考

更新履歴

  • 2019-06-01 初版
  • 2019-06-10 「CI でデプロイするとしばらくエラーに」追加