lucalanca
lucalanca

Reputation: 655

Firebase complex rules

Let's assume I have the following data structure in my Firebase database:

{
  "allProjects": {
    "foo": true,
    "bar": true,
    "baz": true
  },
  "allUsers": {
    "user1": true,
    "user2": true,
    "user3": true
  },
  "projects": {
    "foo": {
      "name": "foo",
      "members": {
        "user1": true
      }
    },
    "bar": {
      "name": "bar",
      "members": {
        "user2": true
      }
    },
    "baz": {
      "name": "baz",
      "members": {
        "user1": true,
        "user3": true
      }
    }
  },
  "users": {
    "user1": {
      "name": "user1"
    },
    "user2": {
      "name": "user2"
    },
    "user3": {
      "name": "user3"
    }
  }
}

Problem

I'm trying to write a few rules so I can protect my data. Here's a few requirements:

  1. Users should only see projects they are part of (i.e. /project/:id/members/:userId === true)
  2. Users should only see users that belong to the same projects as them.

Here's what I was able to come up with:

{
  ".read": false,
  ".write": false,
  "allProjects": {
    ".read": "auth !== null"
  },
  "allUsers": {
    ".read": "auth !== null"
  },
  "projects": {
    "$projectId": {
      // requirement 1
      ".read": "data.child('members').hasChild(auth.uid)"
    }
  },
  "users": {
    "$userId": {
      // requirement 2
      ".read": "???",
    }
  }
}

Upvotes: 2

Views: 742

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598668

The typical approach would be to keep a list of users that each user can see.

user_friends: {
  "user1": {
    "user3": true
  }
  "user3": {
    "user1": true
  }
}

Then as users get added to/removed from projects, you'll need to keep this derived list up to date. Alternatively you can calculate this derived list in a schedule maintenance operation.

Duplicating data like this is one of the big differences between SQL databases and most NoSQL databases. In Firebase we often store extra data to allow for our use-cases. For a great introduction I recommend reading NoSQL data modeling and watching Firebase for SQL developers.

By the way, I noticed that you've combined metadata and the list of users under /projects/$projectid. This is not recommended. For best results, split them into two top-level lists.

  "projects": {
    "foo": {
      "name": "foo",
    },
    "bar": {
      "name": "bar",
    },
    "baz": {
      "name": "baz",
    }
  },
  "members": {
    "foo": {
        "user1": true
    },
    "bar": {
        "user2": true
    },
    "baz": {
        "user1": true,
        "user3": true
    }
  },

Upvotes: 3

Related Questions