iimon TECH BLOG

iimonエンジニアが得られた経験や知識を共有して世の中をイイモンにしていくためのブログです

Firestoreで複合インデックスを作成する方法

こんにちは
エンジニアのタクシです。

Firestoreの複合インデックスの作成方法、関連情報について調査していたのでそのメモをまとめた記事になります。
(今回はインデックスについてのお話のみなので、Firebase・Firestoreの細かい部分などかなり詳細省いているのでご了承ください。。!)

結論

早速ですが結論として、Firestoreで複合インデックスを作成する方法は主に2つあります。

今回は仮にemployeesというコレクションがあるとし、 "age"と"salary"というフィールドで複合インデックスを作成する場合の手順を紹介します。

① Firebaseコンソール上から作成する

Firebaseコンソール画面を開き、Firestore > インデックス を選択します。 そうすると以下のような画面が開けるので、「インデックスを作成」をクリックします。

インデックスを作成をクリックするとモーダル画面が表示されます。 以下の項目を入力していきます。

  • 複合インデックスを作成する対象のコレクションID
    = employees

  • インデックスを作成するフィールド(最低2項目)
    = "age"と"salary"

  • クエリのスコープを選択(コレクションまたはコレクショングループ)
    = コレクション

入力した状態が以下になります。

作成方法自体はシンプルですね!

② Firebase CLIを使って作成する

実際にはまだ試せていないのですが、Firebase CLIを利用して、 インデックスをデプロイすることができるようです。 (firebase cliのインストールが必要です)

こちらの利点としては、インデックスをjsonファイルで定義できるので、管理がしやすそうな点かと思います。

jsonファイルのイメージ

{
  "indexes": [
    {
      "collectionGroup": "employees",
      "queryScope": "COLLECTION",
      "fields": [
        {
          "fieldPath": "age",
          "order": "ASCENDING"
        },
        {
          "fieldPath": "salary",
          "order": "ASCENDING"
        }
      ]
    }
  ]
}

コンソールからもインデックスを作成した場合は、必ずjsonファイルも更新するか、 またはコンソールでは作成しないようにする とルール決めをしないと整合性が取れなさそうなのでそこは要注意ですね!

複合インデックスはどんな時に必要か

複合インデックスが不要な場合

単一フィールドでサポートされるクエリは主に以下のパターンです。

  • 単一フィールドでの等価比較

  • 単一フィールドでの範囲比較

  • 複数フィールドでの等価比較の複合クエリ どのようなことかというと、以下のような場合です。
    (Firestoreのクエリ慣れない方はふーんぐらいで見とけば大丈夫です!)

// ageが20
const ageQuery = employeesRef.where("age", "==", 20);

// ageが20で、salaryが250000
const compositeQuery = employeesRef.where("age", "==", 20).where("salary", "==", 250000);

// ageが20以上
const ageRangeQuery = employeesRef.where("age", ">=", 20);

複合インデックスが必要な場合

  • 等式演算子と不等式演算子 <、<=、>、!= を組み合わせる場合
  • 1フィールドで比較、別フィールドでの昇順・降順の並び替え
// ageが20でsalaryが250000以上
const compositeQuery = employeesRef.where("age", "==", 20).where("salary", ">=", 250000);

// ageが20でsalaryで降順で並び替え
const compositeQuery = employeesRef.where("age", "==", 20).orderBy("salary", "desc");

このように、別フィールドで範囲比較、並び替えなどを実行する場合は基本的には複合インデックスが必要となるようです。

ドキュメントによると、Firestoreはパフォーマンスを考慮し、すべてのクエリに対してインデックスが必要とされます。
単一フィールドのインデックスは自動で定義・維持されますが、複合インデックスが必要なクエリが発行された場合、エラーが出力されます。
エラーにはFirebaseコンソールのインデックス設定へのリンクが埋め込まれていて、クリックするとインデックス作成画面が開きます。

この画面が開きます(以下はイメージです)

開発中の場合などは、すべてのクエリパターンを網羅しなくても、
エラーを見つつインデックス定義を調整して完成版を考える
ということもできるかと思いました。(おそらくほとんどは事前に考えているとは思いますが、、)
ただ、インデックスのエントリ数にも上限がありますし、作ればいい
というわけではもちろんないので、(なかったとしても良くないですし) 不要なインデックスを作成しないでパフォーマンスも落ちない設計をうまくできるように今後も調査・検証は続けようかと思います!

参考:
https://cloud.google.com/firestore/docs/concepts/index-overview https://firebase.google.com/docs/firestore/query-data/indexing