19

I'm studying AngularJS and Firebase and I'm playing with a simple ChatApp, just to understand the code.

My Firebase DB structure is like this:

"chat": {
    "messages": {
        "chat1": { [ list of messages ] },
        "chat2": { [ list of messages ] }
    },
    "rooms": {
        "chat1": {
            "users": {
                "user1": true,
                "user2": true
            }
        },
        "chat2": {
            "users": {
                "user2": true,
                "user3": true
            }
        }
    }
}

Due to Firebase protection Rules I can't add chat link in the user node, than I necessary have to do a Firebase query to retrieve chat rooms for user, using orderByChild() query on App Start Up.

Using Firebase is simple than I can retrieve all chat using:

var chatLink = firebase.database().ref('chat/rooms');
chatLink
  .orderByChild('users/' + userId)
  .equalTo(true)
  .once('value', function(chatSnap){

      /* Do Some Stuff Here */

  });

Every thing work well, but I'm receiving a warning in the console:

FIREBASE WARNING: Using an unspecified index. Consider adding ".indexOn": "users/{userId}" at /chat/rooms to your security rules for better performance

Searching on the web, I found that for variable orderByChild() query, I can user .indexOn: .value in my Firebase Rules.

I've tried to add this Rule:

{
    "rules": {
        "chat": {
            "rooms": {
                ".indexOn": ".value"
            }
        }
    }
}

But I'm still receive always that warning. How can i fix it?

Thank you very much!

AL.
  • 36,815
  • 10
  • 142
  • 281
Marco Cavanna
  • 329
  • 1
  • 5
  • 14
  • You say you've "had to add this rule": ```{ "rules": { "chat": { "rooms": { ".indexOn": ".value" } } } }``` But where and how are you adding it? – Michael T Aug 06 '20 at 09:14

2 Answers2

24

To index this structure to allow efficient querying, you have to add an index for each user:

{
    "rules": {
        "chat": {
            "rooms": {
                ".indexOn": ["users/user1", "users/user2"]
            }
        }
    }
}

That won't be maintainable, since you're likely adding users dynamically.

As usual with NoSQL databases, this means you have to expand/adapt your data model to allow the use-case you want. Instead of querying the rooms for their users, keep a list of the rooms for each user (in addition to your current data):

"user_rooms": {
  "user1": {
    "chat1": true
  },
  "user2": {
    "chat1": true,
    "chat2": true
  }
  "user3": {
    "chat2": true
  }

Now you can look up the chat rooms for a user without even needing to query.

Also see my answer about this categorization problem in Firebase query if child of child contains a value.

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks, but what about rules like ".indexOn": ".value"? I've read that i can use it with variable query, but seems not working in my case... – Marco Cavanna Apr 06 '17 at 16:43
  • 2
    An index on `.value` will work for `orderByValue` queries. Yours is an `orderByChild` query, so it needs an index on each named child. – Frank van Puffelen Apr 06 '17 at 17:01
  • If I wanted to query to find all the users in a chat room using this model, wouldn't we still run into the problem of the missing ".indexOn" value? – jacobsieradzki May 03 '18 at 15:20
16

I am aware that this may be a bit too late but here is something that may help you. I was looking for the same information as you, and in my case, it helped me.

$usersId matches any child key. So you have to do something like this.

{
"rules": {
      "chat": {
          "rooms": {
              "users": {
                  "$usersId": {
                    ".indexOn": ".value"
                }
            }
        }
    }
}

My case:

Using an unspecified index. Consider adding ".indexOn": "date" at messages/-L2bPVX4_fL41H7lhexc to your security and Firebase Database rules for better performance:

L2bPVX4_fL41H7lhexc == child in my NoSQL database structure

solution:

"messages": {
  "$messagesId": {
    ".indexOn": "date"
  }
}
kmoser
  • 8,780
  • 3
  • 24
  • 40
DawidJ
  • 1,245
  • 12
  • 19