👋

Firebase Firestoreでのサブコレクションの Permission について

2024/01/02に公開

Firestore のサブコレクション周りの Permission 設定でちょっと引っかかったのでメモがてら説明します。

サブコレクションの条件と親の条件

下記のようなルールを設定している場合を考えます。

service cloud.firestore {
  match /databases/{database}/documents {
    match /parent/{parentId} {
      allow read, write: if { 条件① };

      match /{subCollection}/{subDoc} {
        allow read, write: if { 条件② };
      }
    }
  }
}

この時 subCollection の subDoc を取得するときの条件は

  • 条件① と 条件② の両方が適用される
  • 条件② のみ適用される

のどちらになるでしょうか。

正解は 条件②のみ適用される が正しいです。

自分はネストされてるからいい感じに 「条件① と 条件② の両方が適用される」 ものと勘違いしてたのですが、これは間違いだったようです。

親のデータを見る必要がある時

この時、 parent のドキュメントには pid というデータがあって、これを request.auth.uid が等しい時だけ read できるようにしたいとします。その時、下記のような Rule を設定することになります。

service cloud.firestore {
  match /databases/{database}/documents {
    match /parent/{parentId} {
      allow read, write: if request.auth != null && resource.data.pid == request.auth.uid;

      match /{subCollection}/{subDoc} {
        allow read, write: if { ??? };
      }
    }
  }
}

この時に、 サブコレクションのデータの読み書きについても 親データに pid == uid が成り立つ時としたい場合の指定の仕方はどうなるでしょうか。 先にも説明した通り親の条件を関係ないため、別途サブコレクション側でも指定する必要があります。

まず、下記の書き方はもちろん違います。サブコレクションのデータの pid を見ようとしてますが、 照らし合わせたいデータは parent の pid です。

service cloud.firestore {
  match /databases/{database}/documents {
    match /parent/{parentId} {
      allow read, write: if request.auth != null && resource.data.pid == request.auth.uid;

      match /{subCollection}/{subDoc} {
        allow read, write: if request.auth != null && resource.data.pid == request.auth.uid;
      }
    }
  }
}

結論としては get を使うことで解決できます。
下記のように get(親のパス).data.pid で取得してこれを uid と比較することができます。

service cloud.firestore {
  match /databases/{database}/documents {
    match /parent/{parentId} {
      allow read, write: if request.auth != null && resource.data.pid == request.auth.uid;

      match /{subCollection}/{subDoc} {
        allow read, write: if request.auth != null && get(/databases/$(database)/documents/parent/$(parentId)).data.pid == request.auth.uid;
      }
    }
  }
}

Discussion