1

firebase^2.2.9

Firebase node looks like that:

{
  articles: {
    "-KcNAv56MZQAr8a_kJYh": {
      topic: 'a',
      text: 'lorem...'
    },
    "-KcNAv5Dd33KE2qfWVFa": {
      topic: 'a',
      text: 'lorem...'
    },
    "-KcNAv5IjjTnmXBCeGFi": {
      topic: 'b',
      text: 'lorem...'
    },
  }
}

Keys generated by firebase push command. I want to retrieve last (chronologically) 20 articles with topic "a". And then paginate.

firebase.root.child('articles')
    .orderByChild('topic')
    .equalTo('a')
    .startAt(offset)
    .limitToLast(20)
    .once('value', snapshot => {...})

There is no way to order by two params (topic and key), so i assume i need to create an index in firebase control panel, which will order articles by topic and by key. So, how do i make it to be ordered by key?

{
  "rules": {
    "articles": {
      ".indexOn": ["topic", ???]
    }
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
stkvtflw
  • 12,092
  • 26
  • 78
  • 155
  • Slightly off topic but yes, you can order by two params. Just add another child node that binds the two together: topic_key. For example topic_key: a_KcNAv56MZQAr8a_kJYh and the next is topic_key: a_KcNAv5Dd33KE2qfWVFa. Then query startingAt(a) and endingAt(a). – Jay Feb 08 '17 at 15:17
  • From [defining data indexes](https://firebase.google.com/docs/database/security/indexing-data#defining_data_indexes): "A node's key is indexed automatically, so there is no need to index it explicitly." – Frank van Puffelen Feb 08 '17 at 15:17
  • What Jay is describing is similar to my answer here: http://stackoverflow.com/questions/26700924/query-based-on-multiple-where-clauses-in-firebase. But I'm not convinced that is needed here. – Frank van Puffelen Feb 08 '17 at 15:19

1 Answers1

0

Firebase Database queries can only order/filter on a single property.

But there is some additional support for pagination in startAt and endAt. When you filter for a specific property value (in your case topic: 'a') that many child nodes may match, you can specify the key of the item at which you want to database to start/end returning values. You pass this key in as the second argument to startAt or endAt.

In your case this turns into:

ref.child('articles')
    .orderByChild('topic')
    .startAt('a')
    .endAt('a', '-KcNAv5Dd33KE2qfWVFa')
    .limitToLast(2)
    .once('value', snapshot => {
      console.log(snapshot.val());
    })

This query gives the last 2 child nodes with topic: 'a' before-and-including item -KcNAv5Dd33KE2qfWVFa, so:

"-KcNAv56MZQAr8a_kJYh"

"-KcNAv5Dd33KE2qfWVFa"

See this jsbin for the working example: http://jsbin.com/bovuyetoki/edit?js,console

Just for completeness, this is the only index I defined:

  "articles": {
    ".indexOn": "topic"
  }
Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • It doesn't sort it properly for some reason. Check this out: https://jsfiddle.net/zsao3rcn/ - first "column" is what i'm getting from firebase as you've suggested, the second column is alphabeticaly sorted keys. As you see, they aren't comming from firebase alphabetically sorted. – stkvtflw Feb 09 '17 at 07:37
  • If you `.orderByChild('topic')`, the results will be ordered by topic. Unless you share the code that produces the problem (similar to the jsbin I shared), there's not a lot more I can do. – Frank van Puffelen Feb 09 '17 at 14:56