0

I'm trying to increase performance in my Firebase Realtime database by creating indices by following recommendations in the console log. Most recommendations are easy to follow, but not all.

My existing rule:

"notes": {
  ".indexOn": ["data/title", "access/author"],
  ".read": "
    auth.uid !== null 
  ",
  "$note_id": {
    ".write": "
      (!data.exists() && auth.uid !== null) ||
      (
        data.child('access').child('author').val() === auth.uid 
      ||
        data.child('access/members').child(auth.uid).exists()
      )
    ",
    "data": {
      ".read": "
        data.parent().child('access').child('author').val() === auth.uid ||
        data.parent().child('access/members').child(auth.uid).exists()
      ",
      ".write": "
        data.parent().child('access').child('author').val() === auth.uid ||
        data.parent().child('access/members').child(auth.uid).exists()          
      ",
    "access" : {
      ".read" : "
        (auth.uid !== null) &&
        (
          data.child('author').val() === auth.uid
          ||
          data.child('members').child(auth.uid).exists()
        )
      ",
    "members" :{
        ".write" : "
          (!data.exists() && auth.uid !== null) ||
          data.parent().child('author').val() === auth.uid ||
          data.parent().child(auth.uid).exists()
        "
      }
    }
  }
},

Some recommendations are for locations that end with the users uid - similar to the below console log:

FIREBASE WARNING: Using an unspecified index.

Consider adding ".indexOn": "access/members/3weT1tYhG456HH0CuC45Muc44ax6" at /notes to your security rules for better performance

Can this index rule be added in Firebase Realtime Database - considering the location locations is ending with user uid string?

A. Nadjar
  • 2,440
  • 2
  • 19
  • 20
Kermit
  • 2,865
  • 3
  • 30
  • 53

1 Answers1

1

Your current data structure makes it easy to find the members for a specific note. It does not make it easy to find the notes for a specific member. To allow that second use-case and ensure it is scalable, you'll want to add an additional data structure:

user_notes: {
  user_id_1: {
    note_id1: true,
    note_id2: true,
    note_id3: true
  },
  user_id_2: {
    note_id3: true,
    note_id4: true,
    note_id5: true
  }
}

With this additional structure you can determine what nodes a user has access to without needing a query.

This of course means you need to write to two locations when you allow a user access to a note, but this is quite common and scalable, and can still be secured with rules.

Also see:

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks @frank for the prompt reply and great answer! :) That seems like a simple enough solution. I already have database listeners in place to do the work. Now I am just wondering how I would go about fetching those notes (not just the id) in a effective manner? – Kermit Aug 31 '19 at 15:25
  • By the way - would you recommend writing data simultaneously (atomic) from the client to update the user_notes node or using a database listener? – Kermit Aug 31 '19 at 15:44
  • 1
    Fetching the actual nodes with the above structure means you'll use a `once()` listener for each. That is not nearly as slow as you may initially think, since Firebase [pipelines the requests over a single connection](http://stackoverflow.com/questions/35931526/speed-up-fetching-posts-for-my-social-network-app-by-using-query-instead-of-obse/35932786#35932786). You could also write the entire note in both places of course, which would duplicate data but make the reads simpler and a bit faster. – Frank van Puffelen Aug 31 '19 at 18:43