マップ フィールドを使用してインデックスの費用を削減

このページでは、マップ フィールドを使用してサブフィールドのグループのインデックス設定を管理する方法について説明します。

未使用のインデックスを削除して、ストレージ コストを削減し、書き込みパフォーマンスを改善することをおすすめします。デフォルトでは、Firestore はドキュメント内のフィールドごとに単一フィールド インデックスを作成します。データベースごとに最大 200 個の単一フィールド インデックス除外を定義することで、単一フィールド インデックスを制御できます。未使用の単一フィールド インデックスをすべて無効にする前に、この上限に達する可能性があります。

除外上限に達しないようにするには、インデックス要件が同じドキュメント フィールドをマップ フィールドの下にグループ化します。これにより、インデックス除外をマップ フィールドに適用でき、同じ除外がマップのサブフィールドに適用されます。

ソリューション: マップ フィールドを使用してインデックスを管理する

game_event ドキュメントのコレクションを使用するアプリがあるとします。次の 2 つのデータモデルについて考えてみます。

最上位のドキュメント フィールド

Node.js
db.collection('game_events').doc().set({
   timestamp: Firestore.FieldValue.serverTimestamp(),
   user_id: 'huDIl8H88kFAFAdcHayf',
   team_id: '6Q5BhBESeTPk8LT0O59I',
   event_type: 'rare_item_drop',
   display_text: 'You found a rare item!',
});

マップ フィールドとサブフィールド

このデータモデルでは、すべてのドキュメント フィールドが details フィールドのサブフィールドになります。

Node.js
db.collection('game_events').doc().set({
  details: {
    timestamp: Firestore.FieldValue.serverTimestamp(),
    user_id: 'huDIl8H88kFAFAdcHayf',
    team_id: '6Q5BhBESeTPk8LT0O59I',
    event_type: 'rare_item_drop',
    display_text: 'You found a rare item!',
  }
});

このアプリは常に、user_idtimestamp、または team_idtimestamp に基づいて、game_event ドキュメントをクエリします。例:

Node.js
let query_user_events = db.collection('game_events')
                          .where('details.user_id', '==', 'huDIl8H88kFAFAdcHayf')
                          .orderBy('details.timestamp');

let query_team_events = db.collection('game_events')
                          .where('details.team_id', '==', '6Q5BhBESeTPk8LT0O59I')
                          .orderBy('details.timestamp');

このアプリについて、次の点に注意してください。

  • アプリは details.user_id, timestampdetails.team_id, timestamp の複合インデックスを利用します。
  • アプリは、timestampuser_idteam_idevent_typedisplay_text の各単一フィールド インデックスを使用しません。

これらのインデックス要件に基づいて、timestampuser_idteam_idevent_typedisplay_text の各単一フィールド インデックスを無効にすることをおすすめします。 次に、2 つのデータモデルに必要な除外を比較します。

最上位フィールドのインデックスの無効化

最上位フィールドのデータモデルで単一フィールド インデックスを無効にするには、フィールドごとに除外を定義する必要があります。除外数が、5 増加します。データモデルに新しいフィールドを追加する場合は、別の除外を定義して単一フィールド インデックスを無効にする必要があります。

サブフィールドのインデックスの無効化

マップとサブフィールド データモデルの単一フィールド インデックスを無効にするには、マップ フィールドに単一の除外を定義します。マップ フィールドに対して除外を指定すると、マップのサブフィールドに同じインデックス設定が適用されます。details フィールドに新しいサブフィールドを追加すると、除外によって自動的に新しいサブフィールドの単一フィールド インデックスが無効になります。

たとえば、Firebase CLI を使用して、このインデックス除外を firestore.indexes.json ファイルに追加し、game_events コレクションの単一フィールド インデックスを無効にします。

{
    "collectionGroup": "game_events",
    "fieldPath": "details",
    "indexes": []
},

後でいずれかのサブフィールドに対して単一フィールド インデックスが必要な場合は、除外によりマップ フィールドのインデックス設定をオーバーライドできます。サブフィールドに対する除外は、そのサブフィールドの継承されたインデックス設定をオーバーライドします。例:

{
    "collectionGroup": "game_events",
    "fieldPath": "details.event_type",
    "indexes": [
      {
        "order": "ASCENDING",
        "queryScope": "COLLECTION"
      },
    ]
},

この方法を使用する場面

上記の例では、マップとサブフィールドの方法により、除外の数が 5 から 1 に減りました。ただし、同様のドキュメント データモデルに 200 のフィールドがあるとします。この方法では、除外の数を 200 から 1 に減らします。

未使用の単一フィールド インデックスを持つ複数のフィールドがドキュメント データモデルに含まれている場合は、マップ フィールドとサブフィールドの方法を使うことを検討してください。 フィールドが多いドキュメントの場合にはこの方法を使用することをおすすめします。