見出し画像

【firebase】【firestore】arrayやmapにreferenceを入れてrulesで縛ってはいけない

というか、SubCollection使えよ、っていう話


nuxt.js + firebaseでPWAアプリを作成しようとしています。

機能の一つとして、友達登録的なことが出来るようにしたくて、firestoreのユーザデータの構造をこんな感じに考えていました。(超簡略)

users
  - document: uid0
    - name: "山田"
    - friends (array)
      - [0] users/uid1 (伊藤さんへのreference)
      - [1] users/uid2 (富田さんへのreference)
  - document: uid1
    - name: "伊藤"
    - friends
      - [0] users/uid0
      - [1] users/uid2
  - document: uid2
    - name: "富田"
    - friends
      - [0] users/uid0
      - [1] users/uid1

友達登録すると、firendsに参照が増えていくイメージ。
functionsで、友達状態は相互関係になるように管理します。
(山田さんのfriendsに伊藤さんがいて、伊藤さんのfriendsに山田さんがいない、という状態にはならない)

セキュリティを考えて、rulesを設定します。
・ログイン者自身のusers、もしくはログイン者がfriendsに含まれるusersは取得できる
・書き込みはログイン者自身のusersだけ

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read: if request.auth.uid != null && (request.auth.uid == userId || /databases/$(database)/documents/users/$(request.auth.uid) in resource.data.friends);
      allow write: if request.auth.uid != null && request.auth.uid == userId;
    }
  }
}

まぁこんなところかな。
「ログイン者がfriendsに含まれるusers」が取得できないと友達一覧とか作れないんでね。

この状態で、ユーザ2名までならうまく動いたんですよ。
上のデータ例でいうと、山田さんと伊藤さんの二人だけで友だちになってたら大丈夫。

ここに富田さんが山田さん・伊藤さん両方と友達登録して、3人全員友達ならそれもOK。

そこから、一人だけ友達状態を解除して、たとえば
山田さんと伊藤さんは友達。
山田さんと富田さんは友達。
伊藤さんと富田さんは友達じゃない。
みたいな状態で、伊藤さんでログインした瞬間に、エラー。

しかもrulesでエラー。なぜ、、、さっきまでうまく行ってたやん。

結論をいいますと、referenceを含むSnapshotを取得した瞬間、データとしてはその参照の先にある参照のデータまで取得してきちゃう様子。

つまり、
1.伊藤さんでログイン
2.自分のfriendsに含まれるreferenceである山田さんのusersを取得
3.山田さんのfriendsのreferenceも自動的に取得しようとする
4.富田さんのデータも取得しようとして、富田さんのfriendsには自分が含まれないから Missing or insufficient permissions.

ということになる。

ただ、参照の先に自分の参照があったら、延々再帰的にデータ取り続けて落ちそうだけど、そうはならない。
参照の先の参照の先の参照の先の・・・・というのが3段階くらいで止まる。
ということは、取得する深度が決まっている。ならば、深度を指定できるんじゃないかなぁ、、、と思うんですが、見つけられませんでした。
(誰か知ってたら教えてください)

なので、こういう構造を作りたかったら、friendsは素直にSubCollectionにしましょう。
それか、stringでuidを入れたarrayにするとか。
反省

この記事が気に入ったらサポートをしてみませんか?