Reputation: 458
I want to query a document reference to see whether or not a document currently exists. If it doesn't exist, then I want to write a new document to that reference.
Unfortunately this isn't working with my security rules. If the document did already exists, then I only want authorised persons to be able to view it. My rules look like this
Firestore rules
function getItemData(item){
return get(/databases/$(database)/documents/equipment/$(item)).data;
}
function getUserData(){
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data;
}
match /equipment/{item}{
allow create: if request.auth != null;
allow read: if !exists(/databases/$(database)/documents/equipment/$(item)) ||
getUserData().clientId == getItemData(item).clientId;
}
Document structure
users > userId: {
clientId: "idhere"
}
equipment > item: {
clientId: "idhere",
serial: "serialnumber"
}
My react native code where i perform the get request
const docRef = firestore.collection("equipment").where('clientId', '==', clientId).where("serial", "==", serial);
docRef.get().then(doc => {
if(!doc.exists){
//add new item to existing document reference
}
}).catch(error => {
//Error here reads "Missing or insufficient persmissions"
})
I can read items if I query them directly. However it seems that my where() functions are conflicting with the rules.
Does anyone have any idea why this would happen?
Edit: If I change my rule to this
match /equipment/{item}
allow read: if true
I'm finding success, so I've definitely confirmed that it is this rule that's causing my problem. When using the simulator, I can access the document directly. It appears that the where statements are the issue
Upvotes: 1
Views: 327
Reputation: 317392
It looks like you're expecting the rule to check, for each document in the result set, if the contents of other documents suggest that it should be readable. The query is failing because security rules are not filters. Please be sure to understand the documentation here. You can't write a rules that removes documents from the requested result set - a query must be all or nothing.
The rule works for document get() requests because the requested document is known ahead of time - {item}
has a specific value. But in the case of a query, the rules aren't able to check each possible document individually. You'll need to find another way of expressing your intent.
Upvotes: 1
Reputation: 598740
If you don't want the user to be able to read the existing document, you shouldn't give them read
permission. And that means that they also won't be able to detect the document's existence by trying to read it.
But you can likely still reach your use-case by only allow the user create
permission if the document doesn't exist yet:
allow create: if request.auth != null && !exists(resource['__name__'])
Now you can have the client simply try to create the document. If that fails, you know the document already existed (or another security rules wasn't met).
Upvotes: 0