46
votes

First, sorry for my terrible English, it is not my native language...

I am building a simple app in Firebase, using the Firestore database. In my app, users are members of small groups. They have access to other users' data. In order not to query too many documents (one per user, in a subcollection of the group's document), I have chosen to add the users' data in an array inside the group's document. Here is my group's document:

{
   "name":"fefefefe",
   "days":[false,false,false,false,true],
   "members":[
       {"email":"[email protected]","id":"aaaaaaaa","name":"Mavireck"}, 
       {"email":"[email protected]","id":"bbbbbbbb","name":"Mavireck2"}, 
   ],
}

How can I check with the security rules if a user is in a group ? Should I use an object instead ? I'd really prefer not use a subcollection for users, because I would reach the free quota's limits too quickly...

Thank you for your time !

EDIT: Thanks for the answer. I will change it to an object : "Members": { uid1 : {}, uid2 : {} }

2

2 Answers

60
votes

In general, you need to write a rule like the following:

service cloud.firestore {
  match /databases/{database}/documents {
    match /collection/{documentId} {
      // works if `members` = [uid1, uid2, uid3]
      // no way to iterate over a collection and check members
      allow read: if request.auth.uid in resource.data.members;
      // you could also have `members` = {uid1: {}, uid2: {}}
      allow read: if resource.data.members[request.auth.uid] != null;
    }
  }
}

You could also use subcollections:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow a user to read a message if the user is in the room
    match /rooms/{roomId} {
      match /documents/{documentId} {
        allow read: if exists(/databases/$(database)/documents/documents/$(documentId)/users/$(request.auth.uid));
      }
      match /users/{userId} {
        // rules to allow users to operate on a document
      }
    }
  }
}
36
votes

I made it happen with this code

Allow some user to read/write some document of a collection if this same user is present into an array of another collection

service cloud.firestore {
  match /databases/{database}/documents {
    match /repositories/{accountId} {
      allow read, write: if request.auth.uid in get(/databases/$(database)/documents/accounts/$(accountId)).data.users
    }
  }
}