【Google Cloud目線】Firestore のルールとインデックスの
書き方・使い方

| 7 min read

📅 今日時点の情報 2026.02.17

📝 記事について: 本記事は、50近辺のくたびれたおっさん(貧乏)の筆者が、サイトやコードを作っていく際に気になったものをまとめたものです。内容の正確性については、必ず公式情報やデータソースをご確認ください。

Cloud Firestoreセキュリティルールインデックスは、データの保護とクエリのパフォーマンスに直結します。ルールは「誰が何を読める・書けるか」を制御し、インデックスは複合クエリを可能にします。書き方・使い方・デプロイの基本を公式情報に沿ってまとめます。

この記事のポイント

  • ルール: match でパスを指定し allow read, write: if 条件request.authresource.datarequest.resource で認証・検証。
  • ルールはフィルタではない: クエリの条件がルールと一致しないと拒否される。取得可能なドキュメントだけを返すクエリを書く。
  • インデックス: 単一フィールドは自動。複合インデックスは等号+範囲・並び替えで必要。エラーのリンクから作成できる。
  • デプロイ: コンソールまたは firebase deploy --only firestorefirestore.rules / firestore.indexes.json)で反映。

1. セキュリティルールの基本構造

ルールは4段の入れ子で書きます。上から「ルールのバージョン → Firestore サービス → データベース内のドキュメント範囲 → コレクションごとの許可条件」です。

  • 1行目 rules_version = '2'; … ルール言語のバージョン。コレクショングループクエリを使う場合は v2 必須。
  • 2行目 service cloud.firestore { ... } … 「この中が Firestore 用のルール」というブロック。
  • 3行目 match /databases/{database}/documents { ... } … どのデータベースのドキュメントに適用するか。{database} は (default) やカスタム DB 名が入る変数。
  • 4行目以降 match /コレクション名/{doc} { allow read, write: if 条件; } … そのコレクション内のドキュメントに対する「読んでよい・書いてよい」の条件。{doc} はドキュメント ID が入る変数。
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

操作は read(= getlist)と write(= createupdatedelete)にまとめて書けます。細かく分けたい場合は allow get, list: if ...;allow create, update: if ...; のように指定します。

Firebase コンソールの Firestore ルール画面。データベース view-tracker、ルールエディタと履歴
Firestore の「ルール」タブ。左に履歴、右にルールエディタ。match でパスを指定し allow read/write で条件を書く

2. 認証とデータ検証

request.auth:クライアントの認証情報です。Firebase Authentication 利用時は request.auth.uid でユーザー ID を取得。「ログイン済みのみ許可」は request.auth != null、「自分のドキュメントだけ」は request.auth.uid == userId(match でキャプチャした変数)のように書きます。

resource.data:既存ドキュメントのフィールドです。読み取り・更新・削除の評価時に参照します。例:resource.data.visibility == 'public' で「public のドキュメントだけ読める」。

request.resource:書き込み後のドキュメントの状態です。create や update で「書ける内容」を検証するときに使います。例:request.resource.data.population > 0 で人口が正の値だけ許可。

他ドキュメントを参照するには get(/databases/$(database)/documents/コレクション/ID)exists(...) が使えます。評価ごとの get/exists 呼び出し数には上限(単一リクエスト 10、複数ドキュメント 20)があるので注意してください。

3. ルールはフィルタではない

重要な注意点: ルールは「返ってくる結果をフィルタする」のではなく、「このクエリで返り得るドキュメントが、すべてルールを満たすか」を評価します。

そのため、allow read: if resource.data.visibility == 'public' だけだと、collection("cities").get()拒否されます(非 public が含まれる可能性があるため)。where("visibility", "==", "public").get() のように、クエリ条件で「public だけ返す」ことを保証すれば許可されます。クエリとルールの条件を一致させる設計にします。

4. インデックス:単一と複合

Firestore はすべてのクエリにインデックスを使います。単一フィールドだけのクエリ(例:where("name", "==", "東京") だけ)は、そのフィールドのインデックスが自動で作られます。複合インデックスは自動では作られず、次のようなクエリで必須です。

複合インデックスがないとエラーになるクエリの例

以下のような書き方をすると、実行時にエラーになり、エラーメッセージに「インデックスを作成する」ための Firebase コンソールのリンクが含まれます。そのリンクを開くと、必要なコレクション・フィールド・昇順/降順がすでに入力されているので、「作成」で追加できます。

  • 等価と範囲の組み合わせ … 例:where("region", "==", "関東").where("population", ">", 100000)。1つは ==、もう1つは < / > などだと複合インデックスが必要。
  • 等価+orderBy(別フィールド) … 例:where("region", "==", "関東").orderBy("population", "desc")。where と orderBy で別のフィールドを指定していると複合インデックスが必要。
  • 複数フィールドで orderBy … 例:orderBy("region").orderBy("population", "desc")。orderBy を2つ以上使う場合も複合インデックスが必要。

逆に、where("name", "==", "東京") だけ、orderBy("createdAt", "desc") だけ、のように1フィールドだけのクエリは単一フィールドインデックスで足りるため、エラーにはなりません。複合インデックスを追加したあとは、構築に数分〜データ量に応じて時間がかかります。

Firestore の複合インデックス作成ダイアログ。コレクションIDとフィールドのパス・昇順/降順を指定
「インデックス」タブの「複合インデックスの作成」。コレクションIDとフィールドパス・並び順を指定。推奨:アプリでクエリを実行して出るリンクから作成すると楽

5. firestore.indexes.json と CLI デプロイ

Firebase の公式ドキュメントでは、複数環境やチームで管理する場合は firestore.indexes.json にインデックス定義を書いてバージョン管理し、firebase deploy --only firestore でデプロイする方法が案内されています。firebase init firestore で雛形が生成されます。個人で1環境だけ使う分には必須ではなく、コンソールやエラー時のリンクから作成すれば十分なことが多いです。便利なのは、チームで同じインデックスを共有したいときや、dev/stg/prod のように複数環境の設定をそろえたいとき。そういう場合に「コードで定義してデプロイ」が役立ちます。

{
  "indexes": [
    {
      "collectionGroup": "cities",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "region", "order": "ASCENDING" },
        { "fieldPath": "population", "order": "DESCENDING" }
      ]
    }
  ]
}

ルールは firestore.rules に記述し、同じ firebase deploy --only firestore でルールとインデックスをまとめてデプロイできます。コンソールで手動追加したインデックスは、ローカルの firestore.indexes.json にも反映しておくと差分が分かりやすくなります(firebase firestore:indexes で一覧取得可能)。

6. ルールのテストとデプロイ

Firebase コンソールの Firestore の「ルール」タブにはルールシミュレータがあります。認証あり/なしや特定のドキュメントパスで read/write をシミュレートでき、エディタ上のルールに対して実行されるので、本番に反映する前に確認すると安心です。ルールの反映には最大約 1 分、既存リスナーへの完全な反映には最大 10 分かかることがあります(公式・デプロイの説明)。

まとめると、ルールで「誰が何を」を制御し、インデックスで複合クエリを有効にします。ルールはクエリと整合させ、複合クエリはエラーリンクまたは firestore.indexes.json で事前に用意しておくのがおすすめです。詳細はセキュリティルール(公式)インデックス(公式)を参照してください。

Artist's Perspective

「ルールもインデックスも、GCP の Cloud Run から実際に書き込んで、ちゃんと動くかテストしてました~~。連携技として、スケジュールで Cloud Run を実行して、条件をいろいろ変えながら DB に書き込んでみる、というやり方です。面白いのが、Web の管理画面でデータベースの中身がリアルタイムに近い形で見えること。ちょっと感動ですよね。」

「ルールやインデックスは、実際にデータベースを使いながら確かめていくと、エラーで弾かれたりするんですよ。その都度ルールを直したり、エラーに出るリンクからインデックスを追加したり……。おっさん、トライ&エラーで覚えていった感じです。」

「まだ基本的なところだけですが、リレーショナルデータベースとか複雑な構造(本で読んだくらいですが笑)、これ使えばできそうですね。」