0

Here's my database structure:

{
  items: {
    'aRandomUid1': {
      data: {
        name: 'theName'
      },
      users: {
        'userUid1': true,
        'userUid2': true
      }
    },

    'aRandomUid2': {
      data: {
        name: 'theName2'
      },
      users: {
        'userUid3': true
      }
    },
    'aRandomUid3': {
      data: {
        name: 'theName3'
      },
      users: {
        'userUid1': true,
        'userUid2': true
      }
    }
  }
}

I want to query all items that a user with uid 'userUid1' has access to:

firebase.database().ref('items')
.orderByChild(`users/${currentUserUid}`)
.equalTo(true)
.on('child_added', (data)=>{
    console.log(data.val())
})

Now, how can I add security rules to allow this query and prevent unauthorized access?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Simon Tran
  • 1,461
  • 1
  • 11
  • 28
  • Your current data structure makes it easy to determine the users for a specific item. It does not however make it easy to find the items for a specific user. To allow that you'll need to introduce an additional data structure where you have each UID at the first level, and then the item IDs under each UID. For an example and longer explanation, see https://stackoverflow.com/questions/40656589/firebase-query-if-child-of-child-contains-a-value – Frank van Puffelen Sep 11 '21 at 03:16
  • @FrankvanPuffelen If I understand correctly, I would need to save the list of item uid for each user? Then, I would individually query each item that the user has access to. Isn't it slower to do multiple query vs querying once /items/ ? – Simon Tran Sep 12 '21 at 20:17
  • Nope, not much slower. See https://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786 – Frank van Puffelen Sep 12 '21 at 20:47
  • The link you provided uses ref.once() to get the value, and Promise.all to resolve all the promises simultaneously. However, ref.on() does not return a promise, how can I query all the items at once? – Simon Tran Sep 13 '21 at 03:48
  • 1
    There is no way to know when "all data" is loaded when using `child_`. You will have to listen for a `value` (with (`on("value"` or `once("value"`) event to allow that, and then use `snapshot.forEach` in the callback to loop over the results. – Frank van Puffelen Sep 13 '21 at 04:00
  • In my app, everytime an item change, it is rerendered on the page. Using ref.on("value") means that on the first render, all the user's items will be rendered one by one. That's why I wanted a way to use Promise,all() with ref.on(). – Simon Tran Sep 13 '21 at 04:33
  • As you've found `on` doesn't return a promise, so you can't use `Promise.all` with it. The reason for that is that a `on` continues listening, so there is no clear moment when it's done. That's why I suggest using `once("value"`, which *does* have a clear moment when it's done. – Frank van Puffelen Sep 13 '21 at 14:52
  • .Since I need to listen to value changes after the initial fetch of items, I should use `once('value')` first, then use `on('value, ()=>{})` to listen to changes? This seems a bit redundant, when according to the firebase doc, calling `ref.once(...)` is equivalent to calling `ref.on()` then `ref.off()` in the callback – Simon Tran Sep 13 '21 at 16:00
  • If you use `on("value"` you can also use the first time it gets called to do you initial work (it's unclear to me what that is in your case, but commonly it's setting up the initial UI). But in that case Firebase doesn't give you a promise to work with, so if you have some code where you want to await a promise - you'll have to return your own promise. – Frank van Puffelen Sep 13 '21 at 16:37

0 Answers0