1

My DB looks like this:

shows{
      show1{
           name:   //Showname
           start:  //Timestamp start
           end:    //Timestamp end
           rating: //Showrating INT
      }
      show2{
           ...
      }
}

How can i query the shows, which are running now (start < now && end > now), ordered by the rating?

Is this even possible with this Database Structure or do i have to change it?

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
I.M
  • 11
  • 2
  • 1
    You can only query on one child node at a time. You could nest your queries but that leads to other timing issues. One option is to combine the times into one node: start_end: 1_3, meaning starting at 1pm and ending at 3pm. – Jay Nov 16 '16 at 23:06
  • I have the similar issue. Is it possible to query only particle certain children for example show1, show3, show10? – Bagusflyer Nov 17 '16 at 03:52
  • @Jay if i combine the timestamps in in one node like you said, how can check if the current server timestamp is in between of this combined timestamp? Doesnt work right..? – I.M Nov 17 '16 at 06:42
  • The server timestamps auto-populate when they are written to Firebase. You could use the completion block (closure) of setValue to get that or just read it in after it's written. Then you could see if it was within the range. So suppose the timestamp is 7. You can then query for nodes 6_8 since you know 7 is between 6 and 8. – Jay Nov 17 '16 at 21:57
  • Just thinking out-loud on this. Generally speaking a timestamp is to 'stamp' an event that happened; when a post was posted, when a user logged in etc. This use case seems to be more 'live' as you are trying to determine if an event that's going on right now is between two times. As one of the answers mentioned, a Date derived from the device may be a better option. If you need to certain about the time, you could also poll one of the time servers available to get the current universal time and then compensate for your locale. – Jay Nov 19 '16 at 14:01

2 Answers2

0

You should name shows' children nodes by their UID, not "show1", "show2", etc. Then you would query your database for the shows ordered by their rating, and use a conditional to test whether each result is within the desired time frame. I haven't actually tested this code, but something like this should work:

ref?.child("shows").child(getUid()).queryOrdered(byChild: "rating").observeEventType(.Value, withBlock: { snapshot in
for child in snapshot.children as? [String: AnyObject] { 
    // filter results
    if (child["start"] <= currentTime && child["end"] >> currentTime ) {
        // results
        resultsArray.append(child)
    }
}

However, I recommend reading about denormalizing data in Firebase first: https://firebase.google.com/docs/database/ios/structure-data https://stackoverflow.com/a/16651115/3502608

And read the docs over querying after you understand denormalization: https://firebase.google.com/docs/database/ios/lists-of-data

Community
  • 1
  • 1
Saoud Rizwan
  • 629
  • 10
  • 20
  • "show1","show2" stands for an autoID. The Query should give me all shows, where "start" is smaller then the current timestamp and "end" is greater then the current timestamp. All these shows should be ordered by their rating. Your query dont include any comparison with the current timestamp – I.M Nov 17 '16 at 06:26
  • This works surely, but you have to know that i have about 100k shows in the DB. Im not sure if its very efficient to load 100k entries from the DB and then loop through all the shows again to check if its in my time range. Do you have any other ideas? Thanks for your answer. – I.M Nov 17 '16 at 15:56
  • Here's an idea: add a new key for your show node called 'dateOfShowing' and then you can use .queryEqualToValue(currentDate) – Saoud Rizwan Nov 17 '16 at 16:07
0

First of all if you are using timestamps and you want to manipulate them in your front end or perform any algorithmic procedure over the timestamp (i.e > or <) then use NSDate not FIRServerValue.timestamp().

To query your show that are having the end : before the current timestamp try using this:-

    let currentTimeStamp = Int(NSDate.timeIntervalSinceReferenceDate*1000)

    FIRDatabase.database().reference().child("shows").queryOrdered(byChild: "end").queryStarting(atValue: currentTimeStamp).observeSingleEvent(of: .value, with: {(Snapshot) in

        print(Snapshot)
    })

This will give you all the shows who are running now. Also for this to work you have to store the value of start and end in similar fashion i.e Int(NSDate.timeIntervalSinceReferenceDate*1000)

To order them according to your show rating , you can only retrieve the values and store them in a struct.

struct show_Struct {

  var name : String!
  var rating : Int! //If it is int or float if it is of type float. 

  ...

   }

Before calling the reloadData() function on any of your tableView or collectionView, just call

let showFeed = [show_Struct]()

..

self.showFeed.sort(by: {$0.rating > $1.rating})
self.tableView.reloadData()
Dravidian
  • 9,945
  • 3
  • 34
  • 74