I'm struggling to figure out how to write my Firestore rules for a sub-collection, and I think this should be doable, but I keep getting permission denied.
I have the following structure
/mycollection/{mainDocument}/subcollection/{subDocument}
Inside {mainDocument}
is a members list. If you're UID is in that list, you have permission to read/write in that document and all the sub-collection documents
To verify my if condition works works at all, I have the following rule which works for the main document but not sub-collections. I can read and write to this document and alter the members within it
match /mycollection/{mainDocument} {
allow read, write: if request.auth.uid in resource.data.members;
}
The documentation says that if you use recursive wildcards on rule_version=2 it will work on any sub-collection and they give this example.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Matches any document in the cities collection as well as any document
// in a subcollection.
match /cities/{city}/{document=**} {
allow read, write: if <condition>;
}
}
}
When I try to use a recursive wildcard though, i get permission denied when I try to read or write to the sub-collection?
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /mycollection/{mainDocument}/{document=**} {
allow read, write: if request.auth.uid in resource.data.members;
}
}
}
or
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /mycollection/{mainDocument=**} {
allow read, write: if request.auth.uid in resource.data.members;
}
}
}
If add an explicit rule for the sub-collection though, then it works, but I can't use my if statement in there as the members list isn't in that sub-collection.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /mycollection/{mainDocument} {
allow read, write: if request.auth.uid in resource.data.members;
}
match /mycollection/{mainDocument}/subcollection/{subDocment} {
allow read, write
}
}
}
}
So I know my rules if open can work on each collection, but I can't get the permission to apply on the sub-collection and only allow it like I can on the {mainDocument}.
It's important to remember that resource
in a rule refers to the specific document being read or written. So when this rule triggers for a document in a subcollection:
match /mycollection/{mainDocument}/{document=**} {
allow read, write: if request.auth.uid in resource.data.members;
}
resource
refers to the document in the subcollection, not the one matched by {mainDocument}
. It's not considering the contents of {mainDocument}
at all.
What you should do is use get()
to access the specific document whose contents must be used to evaluate the rule. Something like this:
match /mycollection/{mainDocument}/{document=**} {
allow read, write: if request.auth.uid in get(/databases/$(database)/documents/mycollection/$(mainDocument)).data.members;
}