Edited at

もう間違えない! Cloud Firestore rulesのresource, request.resource, writeFields

Cloud Firestoreのrulsを書く上でややこしい



  • resource 変数


  • request.resource 変数


  • writeFields 変数

のそれぞれの違いを説明しようと思います。これを見ればもう間違えることはなくなるはず。


TL;DR



  • resource: 現在DBに格納されているドキュメント


  • request.resource: 書き込みを行った場合に期待される将来のドキュメント(の状態)


  • writeFields: 書き込みを行う場合に、書き込もうとしているフィールドのkeyの一覧


それぞれの違い


resource

ドキュメントによると、


resource 変数は要求されたドキュメントを参照し、resource.data はドキュメントに格納されているすべてのフィールドと値のマップです。


とあるので、現在のドキュメントに格納されているフィールドと値のmapを参照できます。

rulesのそれぞれのオペレーションでは以下の通り。


  • read(get, list): 現在のDBに格納されているドキュメント

  • create: undefined

  • update: 現在のDBに格納されているドキュメント

  • delete: 現在のDBに格納されているドキュメント


request.resource


ルールセットが保留中の書き込みを許可する場合は、request.resource 変数にはドキュメントの将来の状態が含められます。ドキュメント フィールドのサブセットのみを変更する update オペレーションの場合、request.resource 変数にはオペレーション後の保留中のドキュメントの状態が含まれます。


つまり、書き込みのオペレーション(crate, update, delete)を実行した後の(保留)ドキュメント状態がmapとして格納される。なので


  • read(get, list): undefined(writeオペレーション時のみ存在するため)

  • create: 新規で書き込むドキュメントのフィールドと値のmap

  • update: 値の追加更新削除をした後の 将来の状態の フィールドと値のmap。

  • delete: undefined

となる。 update の場合は、追加更新削除後の 将来の状態 を表すので、あるオペレーションで既存のデータ {A, B}{C} を書き加えて更新する場合、 request.resource.data には {A, B, C} が含まれる。

一方で


writeFields


List of fields being written in a write request.


とあり、意訳すると、「書き込みリクエスト時に書き込まれるであろうフィールドのリスト」となる。


  • read(get, list): undefined

  • create: 書き込むフィールドのkey (request.resource.data.keys() と一致)

  • update: 今回更新追加削除するフィールドのkey (request.resource.data.keys()必ずしも一致しない 。update時に変更しようとしているフィールドのkeyのみ)

  • delete: undefined


表にしてみる

実際にそれぞれのオペレーションで、現在のフィールド、書き込むフィールドが与えられた時に、resource, request.resourcet, writeFields の値がどう変化するか表にまとめます。


read(get, list)

現在のフィールド
書き込むフィールド
resource
request.resource
writeFields

{
  name: 'mike',
  age: 25
}
undefined
{
  name: 'mike',
  age: 25
}
undefined
undefined


create

現在のフィールド
書き込むフィールド
resource
request.resource
writeFields

undefined
{
  name: 'mike',
  age: 25
}
undefined
{
  name: 'mike',
  age: 25
}
['name', 'age']


update

現在のフィールド
書き込むフィールド
resource
request.resource
writeFields

{
  name: 'mike',
  age: 25
}
{
  company: 'Foobar Inc.'
}
{
  name: 'mike',
  age: 25
}
{
  name: 'mike',
  age: 25,
  company: 'Foobar Inc.'
}
['company']


delete

現在のフィールド
書き込むフィールド
resource
request.resource
writeFields

{
  name: 'mike',
  age: 25
}
undefined
{
  name: 'mike',
  age: 25
}
undefined
undefined


参考