I have a collection /calendars with a subcollection /events. I'm trying to set up rules for querying /events as a Collection Group, but can't seem to access the resource.data fields. All documents in /calendars/events have a field "CalendarId" and for testing purposes I've setup the rules as can be seen below:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/events/{eventId} {
allow read: if 'CalendarId' in resource.data;
}
}
}
I then try to query the /events collection through a Collection Group query:
firestore.collectionGroup('events').where('UserId', '==', userId).get()
But the above query yields me the following error:
FirebaseError: Missing or insufficient permissions
However, if I change the "allow read" rules to the following, the query works and returns the correct documents as expected:
allow read: if !('CalendarId' in resource.data);
Why is it that the 'CalendarId' field is unavailable in the rules even though it is present in all of the /events documents?
For comparison, querying individual /calendars or /events document works great with use of the following rules:
match /calendars/{calendarId} {
allow write: if resource == null || isOwner();
allow read: if resource.data.IsPublic || isOwner();
match /events/{eventId} {
function calendarOwner() {
return get(/databases/$(database)/documents/calendars/$(calendarId)).data.UserId
}
allow write: if request.auth != null && request.auth.uid == calendarOwner();
allow read: if resource.data.IsPublic || (request.auth != null && request.auth.uid == calendarOwner());
}
}
Security rules are not filters, but instead merely detect whether the access is permitted. Since your rule says:
if 'CalendarId' in resource.data;
And your code then does:
firestore.collectionGroup('events').get().where('UserId', '==', userId)
The code violates the rules, since it is requesting potential documents that don't have a CalendarId
field.
You will have to make sure the query has at least the same conditions as your rules check for, for example by checking whether the calendar (if it's a string) is >=
to ""
.