12

Lets say I have two kinds of objects users and accounts. Users can have many Accounts and share them with other Users. So AccountA might be available to User1 and User2. While AccountB is only available to User1. So User1 has two accounts, and User2 has one Account.

What is the "firebase" way to structure this?

I was initially thinking that the users could each store an array of accounts they belong to.

users: {
  1: {
    name: 'Ted',
    accounts: [1, 2]
  }
  2: {
    name: 'Frank',
    accounts: [1]
  }
}

accounts: {
  1: {
    name: "Checking"
  },
  2: {
    name: "Savings"
  }
}

Or the Account would have an array of users.

users: {
  1: {
    name: 'Ted'
  }
  2: {
    name: 'Frank'
  }
}

accounts: {
  1: {
    name: "Checking",
    users: [1, 2]
  },
  2: {
    name: "Savings"
    users: [1]
  }
}

I'm wondering which way lends itself for me to easily find the accounts for a user so that when Ted logs in I can list the accounts he belong to without having to pull down the entire database. For security I don't want all that data on his machine anyway.

Question #1 Would the security rules take care of this? By that I mean I'm planning to set my security rule such that users can only the accounts they belong to. I'm hoping that if I query for "/accounts" I'll get back only those accounts that the user can access... no?

Question #2 Is there a mechanism for querying for a list of items. Like "/accounts/[1,2]" so that I get back the accounts "/accounts/1" and "/accounts/2"?

Thanks for any information you can share.

messivanio
  • 2,263
  • 18
  • 24
rmontgomery429
  • 14,660
  • 17
  • 61
  • 66

1 Answers1

20

Before jumping into specifics, there are a few things you'll want to keep in mind:

  1. You'll typically want to structure your data based on your reading patterns. So if you need to look up all accounts a user is in, you'll need to store that list somewhere. And if you want to look up all users associated with an account, you'll need to store that list somewhere as well. So regarding question #2, Firebase doesn't currently have any generic querying ability (like "/accounts[1,2]"), though this will probably come in the future.
  2. Security rules can't be used to query data either. You're either allowed to read all of the data at a location, or none of it. So regarding your question #1, the security rules won't automatically query /accounts for you.
  3. Security rules don't let you search the contents of an array for an element, but they can check for the existence of a key in an object. Therefore if users 1 and 4 have access to something, you'll probably want to store { 1: true, 4: true } rather than [1, 4].

With that in mind, I'd recommend storing the data like your first example, but without using arrays:

users: {
  1: {
    name: 'Ted',
    accounts: {
      1: true,
      2: true
    }
  }
  2: {
    name: 'Frank',
    accounts: {
      1: true
    }
  }
}

accounts: {
  1: {
    name: "Checking"
  },
  2: {
    name: "Savings"
  }
}

This will let you easily get all of the accounts for a particular user. If you need to also be able to go the other direction (all of the users for an account), you'll have to duplicate that information and store it in the accounts as well. E.g.:

accounts: {
  1: {
    name: "Checking",
    users: {
      1: true,
      2: true
    }
  },
  2: {
    name: "Savings",
    users: {
      1: true
    }
  }
}

Hope this helps!

Michael Lehenbauer
  • 16,229
  • 1
  • 57
  • 59
  • 3
    Could you specify how would you make the request. If u only you have a firebase reference to a specific user. How would you get info about its account – frankelot Apr 05 '15 at 05:38
  • 2
    @feresr you'd need multiple requests - the first to get the list of accounts (/users/1/accounts), and then one for each account you're interested in (to /accounts/n). This is why it's sometimes worth keeping some summary info under /users/x/accounts/y, such as account nickname. – Matt Lyons-Wood Nov 14 '15 at 07:07
  • Okay. I makes sense now. Thanks! – frankelot Nov 14 '15 at 14:50
  • After get the list of keys from ```/users/1/accounts```, I have to use a foreach and perform multiple requests to ```/accounts/id```? There is not a method like ```ref.child('accounts').children(keyArray).once('value')```? My proposal is to get the accounts data in order. – JCarlosR Nov 08 '16 at 18:09