🔥
Firestoreサブコレクションから親コレクションのドキュメントを参照するのに手こずったので共有
同じように手こずった人のための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