1
votes

As I understand it, Firestore does not allow queries within fields of type array, which is a shame. Therefore, if you want to be able to query the contents of an array you have to set up a field as an object type and then set the fields like a map, this is called a nested map. I want to have a map where the key is the ID of another user. Therefore, the database structure is:

database
  users
    {userId}
        friends
           userId1: true
           userId2: true

The 'userId1' and 'userId2' field names will vary depending on the userId of the person listed as a friend.

The question is, how do I write my security rule so I can find my documents (via my {userId}) and the documents of other users where my {userId} is a field in the 'friends' object of the other user's document?

I guess it needs to be something like..

  match /users/{userId} {
      allow read, update, delete: if resource.data.userId == request.auth.uid;
      allow read: if resource.data.friends.{userId} == true;
    }   

But of course this does not work because you cannot seem to use the variable {userId} to name the field that you want to perform a test on. So, if this cannot be done, what is a way to search for documents and have my {userId} stored somehow in someone else's document?


Edit


Well, I think I have the rules determined (see below). However, when trying to test these rules I can't seem to write a Swift call to retrieve data based on that friends object. My Swift call is:

db.collection("users").whereField(FieldPath(["friends.\(userId)"]), isEqualTo: true)

So, my questions are:

  1. Are the rules below correct?
  2. How do I make a Swift call to find the people with a certain userId in the field name of an object type?

    service cloud.firestore { match /databases/{database}/documents { match /users/{documentId} { allow read, write: if isOwner();
    allow read: if getFriend(request.auth.uid) == true;

            function isOwner() {
                return request.auth.uid == resource.auth.uid;
            }
    
            function getFriend(userId) {
                return getUserData().friends[userId]
            }
    
            function getUserData() {
                return get(/databases/$(database)/documents/rooms/{documentId}).data
            }
        } 
    }
    

    }

1

1 Answers

1
votes

I still have not resolved the problem of accessing fields in an object, but it is noted that my Security Rules where generally invalid. You cannot have multiple lines with the same rule type in it, you cannot have multiple lines with 'allow: read' for example. You must use && and ||. For example, the correct definition for the basic rules if you want to check two things are:

// Database rules
service cloud.firestore {
    // Any Cloud Firestore database in the project.
    match /databases/{database}/documents {
        // Handle users
        match /users/{documentId} {
            // The owner can do anything, you can access public data
            allow read: if (isOwner() && isEmailVerified()) || isPublic();
            allow write: if isOwner() && isEmailVerified();

            // Functions //
            function isSignedIn() {
                return request.auth != null;
            }

            function isOwner() {
                return request.auth.uid == resource.data.userId;
            }

            function isPublic() {
                return resource.data.userId == "public";
            }

            function isEmailVerified() {
                return request.auth.token.email_verified
            }      
        } 
    }
}