2

The current query you see below is not efficient because I have not setup the proper indexing. I get the suggestion Consider adding ".indexOn": "users/kxSWLGDxpYgNQNFd3Q5WdoC9XFk2" at /conversations in the console in Xcode. I have tried it an it works.

However, I need the user id after users/ to be dynamic. I've added a link to another post below that has tried a similar thing, but I just can't seem to get it. All help would be much appreciated!

Note: The console output user id above does not match the screenshot below, but does not matter to solve the problem I believe. Correct me if I'm wrong. Thanks!

Here is the structure of my DB in Firebase:

{
  "conversationsMessagesID" : "-KS3Y9dMLXfs3FE4nlm7",
  "date" : "2016-10-19 15:45:32 PDT",
  "dateAsDouble" : 4.6601793282986E8,
  "displayNames" : [ “Tester 1”, “Tester 2” ],
  "hideForUsers" : [ "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
  "readByUsers" : [ "mcOK5wVZoZYlFZZICXWYr3H81az2", "SjZLsTGckoc7ZsyGV3mmwc022J93" ],
  "users" : {
    "SjZLsTGckoc7ZsyGV3mmwc022J93" : true,
    "mcOK5wVZoZYlFZZICXWYr3H81az2" : true
  }
}

and the Swift query:

FIRDatabase.database().reference().child("conversations")
  .queryOrderedByChild("users/\(AppState.sharedInstance.uid!)").queryEqualToValue(true)

Links to other post: How to write .indexOn for dynamic keys in firebase?

Community
  • 1
  • 1
justColbs
  • 1,504
  • 2
  • 18
  • 28
  • 1
    You've included a picture of the JSON tree in your question. Please replace that with the actual JSON as text, which you can easily get by clicking the Export button in your Firebase Database console. Having the JSON as text makes it searchable, allows us to easily use it to test with your actual data and use it in our answer and in general is just a Good Thing to do. – Frank van Puffelen Nov 01 '16 at 03:53
  • Done! @FrankvanPuffelen – justColbs Nov 01 '16 at 03:54
  • I see now how you edited it. didn't know exactly how to do it that way. Thanks so much! – justColbs Nov 01 '16 at 04:02
  • Can you add the changes made in the `Firebase DB rules`? – triandicAnt Nov 01 '16 at 04:02

1 Answers1

6

It seems fairly simple to add the requested index:

{
  "rules": {
    "users": {
      ".indexOn": ["kxSWLGDxpYgNQNFd3Q5WdoC9XFk2", "SjZLsTGckoc7ZsyGV3mmwc022J93", "mcOK5wVZoZYlFZZICXWYr3H81az2"]
    }
  }
}

More likely your concern is that it's not feasible to add these indexes manually, since you're generating the user IDs in your code.

Unfortunately there is no API to generate indexes.

Instead you'll need to model your data differently to allow the query that you want to do. In this case, you want to retrieve the conversations for a specific user. So you'll need to store the conversations for each specific user:

conversationsByUser {
    "SjZLsTGckoc7ZsyGV3mmwc022J93": {
        "-KS3Y9dMLXfs3FE4nlm7": true
    },
    "mcOK5wVZoZYlFZZICXWYr3H81az2": {
        "-KS3Y9dMLXfs3FE4nlm7": true
    }
}

It may at first seem inefficient to store this data multiple times, but it is very common when using NoSQL databases. And is really no different than if the database would auto-generate the indexes for you, except that you have to write the code to update the indexes yourself.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I was afraid of this, but no problem. A quick client change should do the trick. Thank you very much sir! Really appreciate your help in the Firebase community. – justColbs Nov 01 '16 at 04:09
  • Frank I do not see what the security rules would look like for your example of the new model? What would the index be on ? – justColbs Nov 01 '16 at 04:17
  • You don't have to define an index, since you can just get the list of conversations for a user by directly accessing it: `ref.child("conversationByUser").child(user.uid)` – Frank van Puffelen Nov 01 '16 at 04:46
  • We would then have to make a request for each conversations data after the initial request to get all of the user's conversations IDs? Which essentially suggests storing the ID of each conversation in `conversationsByUser`, but not the conversations data. Right? – justColbs Nov 01 '16 at 11:20
  • Yes. Just like in your own example you store the uid of each user (under a conversation), but not the entire user data. – Frank van Puffelen Nov 01 '16 at 14:30