0

I'd like to create an app that has a lot of user data. Let's say that each user tracks their own time per task. If I were to store it flattened it would look like this:

{
    users: {
        USER_ID_1: {
            name: 'Mat',
            tasks: {
                TASK_ID_1: true,
                TASK_ID_2: true,
                ...
            }
        },
    },
    tasks: {
        TASK_ID_1: {
            start: 0,
            end: 1
        },
        TASK_ID_2: {
            start: 1,
            end: 2
        }
    }   
}

Now I'd like to query and get all the task information for the user. Right now the data is small. From their guides: https://www.firebase.com/docs/web/guide/structuring-data.html it says (near the end) "... Until we get into tens of thousands of records..." and then doesn't explain how to handle that.

So my question is as follows. I know we can't do filtering via security, but can I use security to limit what people have access to and then when searching base it off the user id? My structure would then turn to this:

{
    users: {
        USER_ID_1: {
            name: 'Mat'
        }
    },
    tasks: {
        TASK_ID_1: {
            user: USER_ID_1,
            start: 0,
            end: 1
        },
        TASK_ID_2: {
            user: USER_ID_1,
            start: 1,
            end: 2
        },
        ...
    }   
}

Then I would set up my security rules to only allow each task to be accessed by the user who created it, and my ref query would look like this:

var ref = new Firebase("https://MY_FIREBASE.firebaseio.com/");

$scope.tasks = $firebaseArray(ref.child('tasks/')
    .orderByChild('user')
    .startAt('USER_ID_1')
    .endAt('USER_ID_1'));

Is that how I should structure it? My query works but I'm unsure if it'll work once I introduce security where one user can't see another users tasks.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Mathew Berg
  • 28,625
  • 11
  • 69
  • 90

1 Answers1

2

You've already read that security rules can not be used to filter data. Not even creative data modeling can change that. :-)

To properly secure access to your tasks you'll need something like:

"tasks": {
  "$taskid": {
    ".read": "auth.uid === data.child(user).val()"
  }
}

With this each user can only read their own tasks.

But with these rules, your query won't work. At it's most core your query is reading from tasks here:

ref.child('tasks/')...some-filtering...on(...

And since your user does not have read permission on tasks this read operation fails.

If you'd give the user read permission on tasks the read and query would work, but the user could then also read all tasks that you don't want to give them access to.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • That's what I was afraid of! Is there a way around this? Do you have a recommendation on how I can structure my data? The only thing I can think of is hiding all the under each user. p.s. thanks for the quick response :) – Mathew Berg Apr 28 '16 at 15:29
  • 1
    Your initial data structure has a index for each user that enumerates the tasks they have access to. With that you don't need a query, you can just `ref.child('users').child(authData.uid).child('tasks').on(...`. – Frank van Puffelen Apr 28 '16 at 15:34
  • Right but how do I get all the task data? That will let me know what the ids are right? – Mathew Berg Apr 28 '16 at 17:25
  • 1
    You'd join it in. See [this answer from Kato](http://stackoverflow.com/questions/30299972/joining-data-between-paths-based-on-id-using-angularfire). Also see [this answer from me on why these joins are not as slow as you may think](http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786). – Frank van Puffelen Apr 28 '16 at 17:56
  • It's not the speed but the amount of data. From my understanding of firebase.util when you do a join like this it gets all the data and then filters it client side? If that's not true then that's where my mistake is. Also this would mean that people would have access to all the data of tasks, but just not know what user it's associated too right? – Mathew Berg Apr 28 '16 at 18:06
  • Kato's answer contains an approach that extends `$firebaseArray` instead of using firebase-util. – Frank van Puffelen Apr 28 '16 at 18:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110568/discussion-between-mathew-berg-and-frank-van-puffelen). – Mathew Berg Apr 28 '16 at 19:06