【Firebase】Cloud Firestoreの複合クエリを作る
Cloud Firestoreで複合クエリを作る方法と、作成後にfirestore.indexes.json
に反映するやり方です。
複合クエリを作成する
利用したいクエリをコードで実装する
これって複合クエリ必要なの?と考える前に、取り敢えず利用したいクエリを実装してみましょう。
以下のようなDB構成で、特定のユーザが投稿したメモの中から、直近10件のメモを取得するクエリを実行します。
memos: { // コレクション
memoId: { // ドキュメント(ランダムID)
title: string;
body: string;
postUserId: string;
createdAt: Date; // 厳密にはserverTimestamp (FieldValue)
createdAt: Date; // 厳密にはserverTimestamp (FieldValue)
}
...
}
const fetchLatestMemos = async (userId: string) => {
const memosRef = collection(db, 'memos');
const queryOption = [
where('postUserId', '==', userId),
orderBy('updatedAt', 'desc'),
limit(10),
];
const q = query(memosRef, ...queryOption);
const querySnapshot = await getDocs(q);
// 以下取得後の処理のため、省略
}
// ユーザID「123456abcdef」が投稿した直近10件分のメモを取得する
fetchLatestMemos('123456abcdef')
提示されたURLから作成
先程のコードを実行すると、開発者ツールのconsoleに次のようなエラーが表示されます。
Uncaught (in promise) FirebaseError: The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/xxxxx/firestore/indexes?create_composite=xxxxx
at index.esm2017.js:4331
at ns (index.esm2017.js:4331)
at to.onMessage (index.esm2017.js:11277)
at index.esm2017.js:11231
at index.esm2017.js:11254
at index.esm2017.js:15097
at index.esm2017.js:15130
「このクエリはデフォルトで作成されたインデックスでは実行できないので、以下リンクからインデックスを生成してください」
みたいなメッセージです。
リンク先をクリックするとインデックス生成画面に遷移されるので、そのままリンクをクリックしてください。
すると、以下のような画面が表示されるので、そのまま「インデックスを作成」ボタンを押すと複合クエリが作成されます。
作成した複合クエリをfirestore.indexes.jsonに反映
複合クエリを作成したら、以下コマンドでfirestore.indexes.json
に反映しておきましょう。
jsonファイルに書き出しておくことで、開発環境と本番環境で2回複合クエリを作成しなくても、firestore.indexes.json
を反映するだけでプロジェクトに複合クエリを反映できます。
自身のfirebaseを利用しているプロジェクトルート(firestore.indexes.json
と同じ階層)で以下コマンドを実行してください。
firebase firestore:indexes > firestore.indexes.json
すると、firestore.indexes.json
に先程作成した複合クエリが記述されます。
firestore.indexes.jsonをFirebaseプロジェクトに反映
firestore.indexes.json
の内容をプロジェクトに反映したい場合は、以下コマンドで反映できます。
firebase deploy --only firestore:indexes
これでプロジェクトが異なる場合でも、firestore.indexes.json
の内容を反映させるだけで複合クエリが再現できます。
Discussion