Firestoreのruleでdocumentのpathを記述するとき、毎回
/databases/$(database)/documents/...
って書くの大変…。なのでこれをなるべく楽に、安全に記述できる便利関数を紹介する。
第1段階
ひとまず、rootからみて、collection/documentID
となるdocumentのpathの生成を考える。
次のような関数を、match /databases/{database}/documents
の中に記述する。
service cloud.firestore {
match /databases/{database}/documents {
function documentPath(collection, documentID) {
return /databases/$(database)/documents/$(collection)/$(documentID);
}
}
}
これで、例えばpost
モデルのpostID
と合致するpathを生成する場合は、
allow create: if get(documentPath('post', request.resource.data.postID)).data.name == '...';
と記述することができる。
第2段階
第一段階のままだと、root(もしくは任意の基点となるpath)から1階層分のdocmentのpathしか生成できないので、そこから更にサブコレクションのpathを生成しようと思うと都合が悪い。 なので、任意のパラメータを複数渡すことで、多階層のdocumentのpathにも対応できるようにしてみる。
service cloud.firestore {
match /databases/{database}/documents {
function documentPath(paths) {
return path([['databases', database, 'documents'].join('/'), paths.join('/')].join('/'));
}
}
}
解説
path型の変数のままだと、path同士の連結が(現状)うまくできないので、path()
関数を使って、文字列からpathを作るようにする。
['databases', database, 'documents'].join('/')
の部分で、 /databases/$(database)/documents
に相当する文字列を作り、
paths.join('/')
の部分で、rootからの任意のドキュメントのpathの文字列を作り、
そして最後に連結して、path()
関数にてpathを生成する。
例えば、['post', postID, 'authors', authorID]
を与えると、
/databases/$(database)/documents/post/$(postID)/authors/$(authorID)
というpathが生成される。
allow create: if get(documentPath(['post', request.resource.data.postID, 'authors', request.auth.uid])).data.name == '...';
これで、毎回 /databases/
から書くことに解放され、任意のdocumentのpathを生成しやすくなった。