🔍

【Firebase】Cloud Firestoreの複合クエリを作る

2021/11/08に公開

Cloud Firestoreで複合クエリを作る方法と、作成後にfirestore.indexes.jsonに反映するやり方です。

複合クエリを作成する

利用したいクエリをコードで実装する

これって複合クエリ必要なの?と考える前に、取り敢えず利用したいクエリを実装してみましょう。
以下のようなDB構成で、特定のユーザが投稿したメモの中から、直近10件のメモを取得するクエリを実行します。

firestoreの構成
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