こんにちは
エンジニアのタクシです。
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);
複合インデックスが必要な場合
// 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