Firebase Summit のすべての発表内容に目を通し、Firebase を活用してアプリ開発を加速し、自信を持ってアプリを実行できる方法をご確認ください。 詳細

CloudFirestoreのインデックスタイプ

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

インデックスは、データベースのパフォーマンスにおける重要な要素です。本のトピックをページ番号にマップする本のインデックスと同様に、データベース インデックスは、データベース内の項目をデータベース内の位置にマップします。データベースにクエリを送信すると、データベースはインデックスを使用して、要求したアイテムの場所をすばやく検索できます。

このページでは、Cloud Firestore が使用する 2 種類のインデックス、単一フィールド インデックス複合インデックスについて説明します。

すべてのクエリの背後にあるインデックス

クエリのインデックスが存在しない場合、ほとんどのデータベースはアイテムごとにコンテンツをクロールします。これは、データベースが大きくなるにつれてさらに遅くなる遅いプロセスです。 Cloud Firestore は、すべてのクエリにインデックスを使用することで、高いクエリ パフォーマンスを保証します。その結果、クエリのパフォーマンスは、データベース内のアイテムの数ではなく、結果セットのサイズに依存します。

インデックス管理が減り、アプリ開発が増える

Cloud Firestore には、インデックスの管理に費やす時間を短縮する機能が含まれています。最も基本的なクエリに必要なインデックスは、自動的に作成されます。アプリを使用してテストするときに、Cloud Firestore は、アプリに必要な追加のインデックスを特定して作成するのに役立ちます。

インデックスの種類

Cloud Firestore は、単一フィールド複合の 2 種類のインデックスを使用します。インデックスが作成されるフィールドの数に加えて、単一フィールド インデックスと複合インデックスでは、それらの管理方法が異なります。

単一フィールド インデックス

単一フィールド インデックスは、特定のフィールドを含むコレクション内のすべてのドキュメントの並べ替えられたマッピングを格納します。単一フィールド インデックスの各エントリには、特定のフィールドに対するドキュメントの値と、データベース内のドキュメントの場所が記録されます。 Cloud Firestore はこれらのインデックスを使用して、多くの基本的なクエリを実行します。データベースの自動インデックス作成設定とインデックス除外を構成することにより、単一フィールド インデックスを管理します。

自動索引付け

デフォルトでは、Cloud Firestore はドキュメント内の各フィールドとマップ内の各サブフィールドの単一フィールド インデックスを自動的に維持します。 Cloud Firestore は、単一フィールド インデックスに次のデフォルト設定を使用します。

  • 非配列および非マップ フィールドごとに、Cloud Firestore は 2 つのコレクション スコープの単一フィールド インデックスを定義します。1 つは昇順モードで、もう 1 つは降順モードです。

  • マップ フィールドごとに、Cloud Firestore は、マップ内の非配列および非マップ サブフィールドごとに、1 つのコレクション スコープの昇順インデックスと 1 つの降順インデックスを作成します。

  • ドキュメント内の配列フィールドごとに、Cloud Firestore はコレクション スコープの配列を含むインデックスを作成して維持します。

  • コレクション グループ スコープの単一フィールド インデックスは、既定では保持されません。

単一フィールド インデックスの免除

単一フィールド インデックス除外を作成することで、自動インデックス設定からフィールドを除外できます。インデックス作成の除外は、データベース全体の自動インデックス設定をオーバーライドします。除外を使用すると、自動インデックス設定で無効にする単一フィールド インデックスを有効にするか、自動インデックス設定で有効にする単一フィールド インデックスを無効にすることができます。除外が役立つ場合については、インデックス作成のベスト プラクティスを参照してください。

マップ フィールドの単一フィールド インデックス除外を作成すると、マップのサブフィールドはそれらの設定を継承します。ただし、特定のサブフィールドに対して単一フィールド インデックスの除外を定義することはできます。サブフィールドの除外を削除すると、サブフィールドは親の除外設定が存在する場合はそれを継承し、親除外が存在しない場合はデータベース全体の設定を継承します。

単一フィールド インデックスの除外を作成および管理するには、Cloud Firestore でインデックスを管理する を参照してください。

複合インデックス

複合インデックスは、インデックス付けするフィールドの順序付きリストに基づいて、コレクション内のすべてのドキュメントの並べ替えられたマッピングを格納します。

Cloud Firestore は複合インデックスを使用して、単一フィールド インデックスではまだサポートされていないクエリをサポートします。

Cloud Firestore は、考えられるフィールドの組み合わせが多数あるため、単一フィールド インデックスの場合のように複合インデックスを自動的に作成しません。代わりに、Cloud Firestore は、アプリを構築する際に必要な複合インデックスを特定して作成するのに役立ちます。

最初に必要なインデックスを作成せずに上記のクエリを実行しようとすると、Cloud Firestore は、不足しているインデックスを作成するためのリンクを含むエラー メッセージを返します。これは、インデックスでサポートされていないクエリを試行するたびに発生します。コンソールまたはFirebase CLIを使用して、複合インデックスを手動で定義および管理することもできます。複合インデックスの作成と管理の詳細については、「インデックスの管理」を参照してください。

インデックス モードとクエリ スコープ

単一フィールド インデックスと複合インデックスの構成は異なりますが、どちらもインデックス モードとインデックスのクエリ スコープを構成する必要があります。

索引モード

インデックスを定義するときは、インデックス付きフィールドごとにインデックス モードを選択します。各フィールドのインデックス モードは、そのフィールドで特定のクエリ句をサポートします。次のインデックス モードから選択できます。

インデックスモード説明
昇順フィールドで<<===>=>!=in 、およびnot-inクエリ句をサポートし、このフィールド値に基づく昇順での結果の並べ替えをサポートします。
降順フィールドで<<===>=>!=in 、およびnot-inクエリ句をサポートし、このフィールド値に基づく降順での結果の並べ替えをサポートします。
配列の内容フィールドでarray-containsおよびarray-contains-anyクエリ句をサポートします。

クエリのスコープ

各インデックスは、コレクションまたはコレクション グループのいずれかにスコープされます。これは、インデックスのクエリ スコープとして知られています。

コレクションの範囲
Cloud Firestore は、デフォルトでコレクション スコープのインデックスを作成します。これらのインデックスは、単一のコレクションから結果を返すクエリをサポートしています。

コレクション グループのスコープ
コレクション グループには、同じコレクション ID を持つすべてのコレクションが含まれます。コレクション グループからフィルター処理または順序付けされた結果を返すコレクション グループ クエリを実行するには、コレクション グループ スコープで対応するインデックスを作成する必要があります。

索引付けの例

単一フィールド インデックスを自動的に作成することで、Cloud Firestore はアプリケーションが最も基本的なデータベース クエリを迅速にサポートできるようにします。単一フィールド インデックスを使用すると、フィールド値とコンパレータ<<===>=> 、およびin基づいて簡単なクエリを実行できます。配列フィールドの場合、 array-containsおよびarray-contains-anyクエリを実行できます。

説明のために、インデックス作成の観点から次の例を調べます。次のスニペットは、 citiesコレクションにいくつかのcityドキュメントを作成し、各ドキュメントのnamestatecountrycapitalpopulation 、およびtagsフィールドを設定します。

ウェブ
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    regions: ["west_coast", "socal"] });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    regions: ["east_coast"] });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    regions: ["kanto", "honshu"] });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    regions: ["jingjinji", "hebei"] });

デフォルトの自動インデックス設定を前提として、Cloud Firestore は、配列以外のフィールドごとに 1 つの昇順の単一フィールド インデックス、非配列フィールドごとに 1 つの降順の単一フィールド インデックス、および配列フィールドの 1 つの配列を含む単一フィールド インデックスを更新します。次の表の各行は、単一フィールド インデックスのエントリを表します。

コレクション索引付けされたフィールドクエリ範囲
都市名前コレクション
都市状態コレクション
都市コレクション
都市キャピタルコレクション
都市人口コレクション
都市名前コレクション
都市状態コレクション
都市コレクション
都市キャピタルコレクション
都市人口コレクション
都市array-contains領域コレクション

単一フィールド インデックスでサポートされるクエリ

これらの自動作成された単一フィールド インデックスを使用して、次のような単純なクエリを実行できます。

ウェブ
const stateQuery = citiesRef.where("state", "==", "CA");
const populationQuery = citiesRef.where("population", "<", 100000);
const nameQuery = citiesRef.where("name", ">=", "San Francisco");

inおよび複合等価 ( == ) クエリを作成することもできます。

ウェブ
citiesRef.where('country', 'in', ["USA", "Japan", "China"])

// Compound equality queries
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA")
         .where("capital", "==", false)
         .where("state", "==", "CA")
         .where("population", "==", 860000)

範囲比較 ( <<=> 、または>= ) を使用する複合クエリを実行する必要がある場合、または別のフィールドで並べ替える必要がある場合は、そのクエリの複合インデックスを作成する必要があります。

array-containsインデックスを使用すると、 regions配列フィールドを照会できます。

ウェブ
citiesRef.where("regions", "array-contains", "west_coast")
// array-contains-any and array-contains use the same indexes
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])

複合インデックスでサポートされるクエリ

Cloud Firestore は複合インデックスを使用して、単一フィールド インデックスではまだサポートされていない複合クエリをサポートします。たとえば、次のクエリには複合インデックスが必要です。

ウェブ
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)
// in and == clauses use the same index
citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)

これらのクエリには、以下の複合インデックスが必要です。クエリではcountryフィールドに等式 ( ==またはin ) が使用されるため、このフィールドには昇順または降順のインデックス モードを使用できます。デフォルトでは、不等式句は、不等式句のフィールドに基づいて昇順のソート順を適用します。

コレクション索引付けされたフィールドクエリ範囲
都市 (または ) 国、 人口コレクション

同じクエリを降順で実行するには、 populationの降順で追加の複合インデックスが必要です。

ウェブ
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")

citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)
         .orderBy("population", "desc")
コレクション索引付けされたフィールドクエリ範囲
都市国、 人口コレクション
都市, 人口コレクション

また、 array-containsまたはarray-contains-anyクエリを追加の句と組み合わせるには、複合インデックスを作成する必要があります。

ウェブ
citiesRef.where("regions", "array-contains", "east_coast")
         .where("capital", "==", true)

// array-contains-any and array-contains use the same index
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
         .where("capital", "==", true)
コレクション索引付けされたフィールドクエリ範囲
都市array-containsタグ、 (または ) 大文字コレクション

コレクション グループ インデックスでサポートされるクエリ

コレクション グループ スコープのインデックスを示すために、いくつかのcityドキュメントにlandmarksサブコレクションを追加することを想像してください。

ウェブ
var citiesRef = db.collection("cities");

citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Bridge",
    category : "bridge" });
citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Park",
    category : "park" });

citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Gallery of Art",
    category : "museum" });
citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Mall",
    category : "park" });

コレクション スコープで次の単一フィールド インデックスを使用すると、 categoryフィールドに基づいて単一都市のlandmarksコレクションをクエリできます。

コレクション索引付けされたフィールドクエリ範囲
ランドマーク (または ) カテゴリコレクション
ウェブ
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

ここで、すべての都市のランドマークをクエリすることに関心があるとします。すべてのlandmarksコレクションで構成されるコレクション グループに対してこのクエリを実行するには、コレクション グループ スコープでlandmarks単一フィールド インデックスを有効にする必要があります。

コレクション索引付けされたフィールドクエリ範囲
ランドマーク (または ) カテゴリコレクショングループ

このインデックスを有効にすると、 landmarksコレクション グループに対してクエリを実行できます。

ウェブ
var landmarksGroupRef = db.collectionGroup("landmarks");

landmarksGroupRef.where("category", "==", "park")
landmarksGroupRef.where("category", "in", ["park", "museum"])

フィルター処理または順序付けされた結果を返すコレクション グループ クエリを実行するには、対応する単一フィールドまたは複合インデックスをコレクション グループ スコープで有効にする必要があります。ただし、結果のフィルター処理や順序付けを行わないコレクション グループ クエリには、追加のインデックス定義は必要ありません。

たとえば、追加のインデックスを有効にせずに、次のコレクション グループ クエリを実行できます。

ウェブ
db.collectionGroup("landmarks").get()

索引項目

プロジェクトの構成済みインデックスとドキュメントの構造によって、ドキュメントのインデックス エントリの数が決まります。インデックス エントリは、インデックス エントリ数の制限にカウントされます。

次の例は、ドキュメントのインデックス エントリを示しています。

書類

/cities/SF

city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]

単一フィールド インデックス

  • 都市名 ASC
  • 都市名 DESC
  • 温度.夏のASC
  • 温度.夏 DESC
  • 温度.冬の ASC
  • 気温.冬 DESC
  • 近隣配列の内容 (ASC および DESC)

複合インデックス

  • city_name ASC、近隣 ARRAY
  • city_name DESC、近隣 ARRAY

索引項目

このインデックス設定により、ドキュメントの次の 18 のインデックス エントリが作成されます。

索引インデックス付きデータ
単一フィールド インデックス エントリ
都市名 ASC city_name: "サンフランシスコ"
都市名 DESC city_name: "サンフランシスコ"
温度.夏のASC温度.夏: 67
温度.夏 DESC温度.夏: 67
温度.冬の ASC温度.冬: 55
気温.冬 DESC温度.冬: 55
近所の配列にはASCが含まれています近所:「ミッション」
近所の配列にはDESCが含まれています近所:「ミッション」
近所の配列にはASCが含まれています近所:「ダウンタウン」
近所の配列にはDESCが含まれています近所:「ダウンタウン」
近所の配列にはASCが含まれています近所:「マリーナ」
近所の配列にはDESCが含まれています近所:「マリーナ」
複合インデックス エントリ
city_name ASC、近隣 ARRAY city_name: 「サンフランシスコ」、neighbords: 「ミッション」
city_name ASC、近隣 ARRAY city_name: 「サンフランシスコ」、neighborhoods: 「ダウンタウン」
city_name ASC、近隣 ARRAY city_name: 「サンフランシスコ」、neighbords: 「マリーナ」
city_name DESC、近隣 ARRAY city_name: 「サンフランシスコ」、neighbords: 「ミッション」
city_name DESC、近隣 ARRAY city_name: 「サンフランシスコ」、neighborhoods: 「ダウンタウン」
city_name DESC、近隣 ARRAY city_name: 「サンフランシスコ」、neighbords: 「マリーナ」

インデックスと価格

インデックスは、アプリケーションのストレージ コストに影響します。インデックスのストレージ サイズの計算方法の詳細については、「インデックス エントリのサイズ」を参照してください。

インデックスのマージを利用する

Cloud Firestore はすべてのクエリにインデックスを使用しますが、必ずしもクエリごとに 1 つのインデックスを必要とするわけではありません。複数の等価 ( == ) 句と、オプションでorderBy句を含むクエリの場合、Cloud Firestore は既存のインデックスを再利用できます。 Cloud Firestore は、単純な等値フィルタのインデックスをマージして、より大きな等値クエリに必要な複合インデックスを構築できます。

インデックスのマージを利用できる状況を特定することで、インデックス作成のコストを削減できます。たとえば、レストラン評価アプリのrestaurantsコレクションを想像してみてください。

  • レストラン

    • バーガータイム

      name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

ここで、このアプリが以下のようなクエリを使用しているとします。このアプリは、常にstar_ratingの昇順でソートしながら、 categorycityeditors_pickの等式句の組み合わせを使用していることに注意してください。

ウェブ
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

クエリごとにインデックスを作成できます。

コレクション索引付けされたフィールドクエリ範囲
レストランカテゴリ、 star_ratingコレクション
レストラン都市、 star_ratingコレクション
レストランカテゴリ、 都市、 star_ratingコレクション
レストランカテゴリ、 都市、 editors_pick、 star_ratingコレクション

より良い解決策として、等式句のインデックスをマージする Cloud Firestore の機能を利用して、インデックスの数を減らすことができます。

コレクション索引付けされたフィールドクエリ範囲
レストランカテゴリ、 star_ratingコレクション
レストラン都市、 star_ratingコレクション
レストラン editors_pick, star_ratingコレクション

この一連のインデックスが小さいだけでなく、追加のクエリもサポートしています。

ウェブ
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

インデックス作成の制限

インデックスには次の制限が適用されます。すべてのクォータと制限については、「クォータと制限」を参照してください。

リミット詳細
データベースの複合インデックスの最大数

200

サポートに連絡して、この制限の引き上げをリクエストできます。

データベースの単一フィールド構成の最大数

200

合計 200 のフィールド レベルの構成が許可されます。 1 つのフィールド構成に、同じフィールドの複数の構成を含めることができます。たとえば、単一フィールドのインデックス作成免除と同じフィールドの TTL ポリシーは、制限に対して 1 つのフィールド構成としてカウントされます。

各ドキュメントのインデックス エントリの最大数

40,000

インデックス エントリの数は、ドキュメントの次の合計です。

  • 単一フィールド インデックス エントリの数
  • 複合インデックス エントリの数

Cloud Firestore がドキュメントと一連のインデックスをインデックス エントリに変換する方法については、こちらのインデックス エントリ数の例をご覧ください。

複合インデックス内のフィールドの最大数100
インデックス エントリの最大サイズ

7.5KiB

Cloud Firestore がインデックス エントリのサイズを計算する方法については、インデックスエントリのサイズをご覧ください。

ドキュメントのインデックス エントリのサイズの最大合計

8 MiB

合計サイズは、ドキュメントの次の合計です。

  • ドキュメントの単一フィールド インデックス エントリのサイズの合計
  • ドキュメントの複合インデックス エントリのサイズの合計
  • インデックス付きフィールド値の最大サイズ

    1500バイト

    1500 バイトを超えるフィールド値は切り捨てられます。切り捨てられたフィールド値を含むクエリは、一貫性のない結果を返す場合があります。

    インデックス作成のベスト プラクティス

    ほとんどのアプリでは、自動インデックス作成とエラー メッセージ リンクを使用してインデックスを管理できます。ただし、次の場合は、単一フィールドの除外を追加することをお勧めします。

    場合説明
    大きな文字列フィールド

    クエリに使用しない長い文字列値を保持することが多い文字列フィールドがある場合は、そのフィールドをインデックス作成から除外することで、ストレージ コストを削減できます。

    連続した値を持つドキュメントを含むコレクションへの高い書き込み率

    タイムスタンプのように、コレクション内のドキュメント間で順次増加または減少するフィールドにインデックスを付ける場合、コレクションへの最大書き込み速度は 1 秒あたり 500 書き込みです。連続した値を持つフィールドに基づいてクエリを実行しない場合は、フィールドをインデックス作成から除外して、この制限を回避できます。

    たとえば、書き込み率が高い IoT ユースケースでは、タイムスタンプ フィールドを持つドキュメントを含むコレクションが、1 秒あたり 500 回の書き込み制限に近づく可能性があります。

    TTL フィールド

    TTL (time-to-live) ポリシーを使用する場合、TTL フィールドはタイムスタンプでなければならないことに注意してください。 TTL フィールドのインデックス作成はデフォルトで有効になっており、トラフィック レートが高くなるとパフォーマンスに影響を与える可能性があります。ベスト プラクティスとして、TTL フィールドに単一フィールドの除外を追加します。

    大きな配列またはマップ フィールド

    大きな配列またはマップ フィールドは、ドキュメントあたり 40,000 のインデックス エントリの制限に近づく可能性があります。大規模な配列またはマップ フィールドに基づいてクエリを実行していない場合は、インデックス作成から除外する必要があります。