Jacob Phillips
Jacob Phillips

Reputation: 9264

Firebase: How to structure public/private user data

Naturally the users in my database have information that can be publicly accessible and other information only they should see. I'm considering two different ways to implement this.

Option 1: Have /users/$uid readable only by that user and have /users/$uid/profile be readable by anyone.

Option 2: Keep /users/$uid readable only by that user and have a /profiles/$uid that is public. This follows the recommendation for a flatter data structure, but I don't see how it is better in this case.

Upvotes: 12

Views: 5350

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

The easiest way to see why the "flatter" structure is better is to look at how you'd secure it and how you'd then implement functionality.

Your first structure is:

users: {
  uidOfJacob: {
    stackId: 884522,
    ssn: "999-99-9999",
    profile: {
      displayName: "Jacob Philips"
    }

  },
  uidOfPuf: {
    stackId: 209103,
    ssn: "999-99-9999",
    profile: {
      displayName: "Frank van Puffelen"
    }
  }
}

You'd secure it with:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth.uid == $uid",
        ".write": "auth.uid == $uid"
        "profile": {
          ".read": true
        }
      }
    }
  }
}

One of the main reasons for having public information is to be able to show a list of that information. In JavaScript:

ref.child('users').child(???).child('profile').on('child_added'...

This won't work, because what do we put in ???. Firebase operations need to be able to read the entire list from one location, and the user needs to have read permission on that entire location (not just to the individual child nodes).

If we structure the data to separate the public information from the private information, we get:

users: {
  uidOfJacob: {
    stackId: 884522,
    ssn: "999-99-9999",
    profile: {
      displayName: "Jacob Philips"
    }

  },
  uidOfPuf: {
    stackId: 209103,
    ssn: "999-99-9999",
    profile: {
      displayName: "Frank van Puffelen"
    }
  }
},
"profile": {
  uidOfJacob: {
    displayName: "Jacob Philips"
  },
  uidOfPuf: {
    displayName: "Frank van Puffelen"
  }
}

You'd secure it with:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth.uid == $uid",
        ".write": "auth.uid == $uid"
      }
    },
    "profiles": {
      ".read": true,
      "$uid": {
        ".write": "auth.uid == $uid"
      }
    }
  }
}

Now to get a list of the public user profiles, you'd do:

ref.child('profiles').on('child_added'...

This will work, because everyone has read permission on profiles.

Upvotes: 27

Related Questions