Cloud Firestore Rule
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /admins/{document=**} {
allow read, write: if true;
}
match /{userId}/{document=**} {
allow read, write: if request.auth.uid == userId || get(/databases/$(database)/documents/$(userId)/users/$(request.auth.token.email)).exists;
}
}
}
Details provided in Rules Playground of Cloud Firestore
Simulation type: get
Location: /databases/(default)/documents/cTgy9W6Zt2dShSgqig2ToeYLEzt2/products
Authenticated: True
{
"uid": "dQkped8ggvUv6iHfI9kVD7Vrnlf2",
"token": {
"sub": "dQkped8ggvUv6iHfI9kVD7Vrnlf2",
"aud": "undefined",
"email": "abc@example.com",
"email_verified": false,
"firebase": {
"sign_in_provider": "password"
}
}
}
Error
Function [get] called with malformed path: /databases/(default)/documents/cTgy9W6Zt2dShSgqig2ToeYLEzt2/users/abc@example.com
You need to pass a Document path to the get()
method.
As explained in the doc: "The get()
and exists()
functions both expect fully specified document paths."
With
/databases/$(database)/documents/$(userId)/users/$(request.auth.token.email)
you are actually passing a Collection path (3 elements).
You need to change your data model or add a document in the abc@example.com
subcollection to point to.
In addition I think you're mixing up the get()
and exists()
functions.
The get()
method returns a rules.firestore.Resource
which does not have an exists
property.
So doing get(**path**).exists
cannot work. You should either use exists()
to check if a specific document exists or use get()
to check the value of a field of the specific document through the data
property.