Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 577
Jacob Phillips Avatar asked Jul 29 '16 00:07

Jacob Phillips


People also ask

What is the correct Firebase database structure?

All Firebase Realtime Database data is stored as JSON objects. You can think of the database as a cloud-hosted JSON tree. Unlike a SQL database, there are no tables or records. When you add data to the JSON tree, it becomes a node in the existing JSON structure with an associated key.

Does Firebase have schema?

Firebase security rules, this video does an amazing job explaining them, are a way in which you can sort of create schemas. An important consideration when using these rules is that if you're using the Firestore Admin SDK (used for backend code) then your rules will be bypassed.

Can Firebase handle 10 million users?

The limit you're referring to is the limit for the number of concurrently connected users to Firebase Realtime Database on the free Spark plan. Once you upgrade to a payment plan, your project will allow 200,000 simultaneously connected users.


1 Answers

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.

like image 132
Frank van Puffelen Avatar answered Nov 15 '22 18:11

Frank van Puffelen