Richie Richie - 6 months ago 156
Swift Question

query mid-section of firebase database in swift

I'm using firebase for a large-ish database, with each entry using an autoid key. To get, say, the last ten entries, I can use:

ref.queryLimitedToLast(10).observeSingleEventOfType(.Value, withBlock: { snapshot in
for item in snapshot.children {
//do some code to each item
}
})


However, I can't for the life of me work out how to then get just the ten entries before that. Eg. if the database had 100 entries, my code would return 90-100, but how would I then get entries 80-90 (without, for example, querying the last 20 and throwing half away, as it seems inefficient)?

Edit:
I ended up using

ref.queryOrderedByChild("timecode").queryEndingAtValue(final).queryLimitedToLast(10).observeSingleEventOfType(.Value, withBlock: { snapshot in
for item in snapshot.children {
//do some code to each item, including saving a new value of 'final'
}
})


and saving the value 'final' as the timecode of the last update. that is, first i would get results, 90-100, say, and save the timecode of 90 as final (minus one second), then use this for the ending value, etc... to find results 80-89.
Just as Jay describes below, but using a timestamp instead of an index number (as it was already in there)

Edit 2:
Also, to get it working better, I also added ".indexOn": "timecode" to the firebase rules for the database

Jay Jay
Answer

There's a couple of ways to do this but an easy solution is to keep a total_count in another node and an index within each node.

Then use queryStartingAtValue and queryEndingAtValue to query the range of child nodes you are interested in.

When you add a child to your 'posts' node for example, add one to the total_count node and save it. Over time you'll have 100 posts and the total_count node will have a value of 100. You can then query for any range of posts: .queryStartingAtValue(80) and . queryEndingAtValue(89), or .queryStartingAt(20) and .queryEndingAt(30)

For example, assume there's 45 posts (showing just 4 of them here)

posts
  ...
  post_1024
    text: "my post!"
    index: 42
  post_1025
    text: "another post"
    index: 43
  post_1026
    text: "yippee"
    index: 44
  post_1027
    text: "Stuff and Things"
    index: 45

and then a node to track them

post_info
   total_count: 45

and the code to query for the middle two nodes

let ref = myRootRef.childByAppendingPath("posts"
ref.queryOrderedByChild("index").queryStartingAtValue(43).queryEndingAtValue(44)
   .observeEventType(.Value, withBlock: { snapshot in
    print(snapshot.key)
})

and the output would be

  post_1025
    text: "another post"
    index: 43
  post_1026
    text: "yippee"
    index: 44

That being said, this may be slightly redundant depending on what happens to your data. If you never delete posts, then you're set. However, if you delete posts then obviously there's a gap in your indexes (42, 43, .. 45) so other factors need to be taken into consideration.

You may not even need a total_count - it just depends on how your app works.

You could also leverage the priority variable on your nodes to store the index instead of having it be a child node.

Transitions and .observeSingleEvent with .Value and .numChildren can be also be used to obtain a live node count.