🔥

Firestoreサブコレクションから親コレクションのドキュメントを参照するのに手こずったので共有

2025/03/12に公開

同じように手こずった人のためのNG例とOK例をさっと紹介します。粗削り記事ですがご容赦。

結論、Firestoreのセキュリティルールにおいて、サブコレクションのルールから親コレクションのドキュメントを参にする場合は、基本的にパスのパラメータを使う必要があります

こんな感じ。

match /parentCollection/{parentDocId}/subCollection/{subDocId} {
  allow read, write: if get(/databases/$(database)/documents/parentCollection/$(resource.data.parentId)).exists;
}

用は、match行の中に親コレクションとそのドキュメントIDを含めるべきということです。

NG例とOK例を紹介します

なお、状況としては、

  • postsコレクションのサブコレクションとしてcommentsがある
  • commentsのフィールドpost_idには親postのIDがある

ものとします。

NG例(失敗するパターン)

以下は動作しません:

match /posts/{postId}/comments/{commentId} {
  allow get: if exists(/databases/$(database)/documents/posts/$(resource.data.post_id));
}

これをするためにもcommentsのフィールドとしてpost_idを持たせたのですが、意味はなかったようです。ただそれ以外にも有用なので良いとしますが。

こうなる原因は、参照方法にあります。Firestoreはドキュメントのデータに基づいた動的なパス参照(resource.data.post_idによる参照)ができないからです。

正しい書き方(解決方法)

Firestoreのサブコレクション設計で親ドキュメントの情報を参照したい場合は、必ずパスの変数を使用します:

match /posts/{postId}/comments/{commentId} {
  allow get: if exists(/databases/$(database)/documents/posts/$(eventId));
}

つまり、Firestoreルールでは以下が前提となります:

  • 親ドキュメントのID(postId)をサブコレクションのパスに含める設計にする必要があります。

その他学び

  • 本件趣旨とはずれるが、そもそもサブコレクションは基本的に使わなくて良いということだろう。どうしてもサブコレクションを使わなければいけない理由があるときだけ使うべきだと思った。今回の私のケースではドキュメント数が多くなるのでそのパフォーマンスを考えるとサブコレクションとして実装するほうが良いだろうという判断だったが、他の理由でサブコレクションにすることはもう無いだろう。

Discussion