I have the data in the following structure:
stage/data/groups(coll)/
group_name
group_id
participants(coll)/userid
My requirement is to write the firebase rule with the following condition.
I have tried the following rule, but it doesn't help.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isAuthorised(document){
return exists(/document/participants/$(request.auth.uid))
}
match /{document=**} {
allow read, write: if isAuthorised(document);
}
}
}
I would just iterate the list and return only a valid list if it is an ASP.NET API code. As I am new to Firebase, I am learning the complex rules to protect the data.
Edited: Updated the rule as below, it works if I pass the hardcoded group id instead of passing "$(groupid)" to the exists validation method.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isAuthenticated(){
return request.auth.uid != null;
}
match /{document=**}/groups/{groupid} {
allow read, write: if
isAuthenticated() &&
exists(/databases/$(database)/documents/stage/data/groups/$(groupid)/participants/$(request.auth.uid));
}
match /{document=**}/users/{userid} {
allow read, write: if true;
}
}
}
The flutter code I am trying to access the groups.
final groupList = await ref.collection(Constants.Environment)
.doc("data")
.collection("groups").get();
var docs = groupList.docs.toList();
From the example in the documentation, it seems that exists
requires the full path of the document you want to check on. You're passing a relative path, which won't work.
function isAuthorised(document){
return exists(/databases/$(database)/documents/participants/$(request.auth.uid))
}
Update: the query you added will never work with your rules as rules are not filters (read the link please). Rather rules ensure that the data that your code accesses matches your requirements. In this case, this requirement of your rules is not matches by the code:
exists(/databases/$(database)/documents/stage/data/groups/$(groupid)/participants/$(request.auth.uid))
When you access a single document, the rules engine may be able to check this condition. But it can never do that for a list-call, as it'd have to check each individual group to see if its subcollection has a matching document. This wouldn't scale, so is not possible.
The typical approach is to add an array of participants in each groups
document. If that won't work for your use-case, consider storing a reverse index in the data, so a list of the groups for each UID:
userGroups (collection)
$uid (docs)
groupIds (collection)
$groupId