Access parent documents field in Firestore rules
Building upon Dan's answer, you should be able to reduce the number of reads on your database for update
and delete
on the subcollection by adding the creatorUID to the subcollection document.
You'll have to restrict create
to just the creator and make sure the creatorUID is set. Here's my modification of Dan's rules:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipe} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData() {
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
}
match /List/{list} {
allow read: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
allow create: if recipeData().creatorUID == request.auth.uid
&& request.resource.data.creatorUID == request.auth.uid;
}
}
}
}
Rules don't cascade, so you'll need to perform whatever checks you need for the document being captured by the Rules.
Generally speaking, {x=**}
rules are more often a mistake and the usage of =**
only for extremely specific use cases.
From your question, I'm assuming your data mode is something like this:
/ListofRecipes/{recipe_document}/List/{list_document}
In this case, you'll need your Rules to be configured something like this:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipe} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData() {
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
}
match /List/{list} {
allow read: if isSignedIn();
allow write: if recipeData().creatorUID == request.auth.uid;
}
}
}
}
Dan's answer above works great! Just for reference, in my case I only needed the root parent document ID, you can use the variable from the match statement above the nested one, like this:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipeID} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
match /List/{list} {
allow read: if isSignedIn();
allow write: if recipeID == 'XXXXX';
}
}
}
}