AlexM AlexM - 3 months ago 80
Swift Question

Server side filtering of Firebase data

I have a Firebase db structure as follows:

{
"listings" : {
"-KOt8OUGkUphoMyqEXJ2" : {
"created" : 1470911323208,
"ends" : 1470911323209,
"make" : "LONDON TAXIS INT",
"model" : "TX4 BRONZE",
"status" : "For Sale",
},
"-KOt97_P8sJW7woED4aH" : {
"created" : 1470911515115,
"ends" : 1471775515000,
"make" : "NISSAN",
"model" : "QASHQAI N-TEC",
"status" : "For Sale",
},
"-KOt_BYYUEaXu_LNvnUv" : {
"created" : 1470918609414,
"ends" : 1471782609000,
"make" : "MAZDA",
"model" : "3 TS",
"status" : "For Sale",
}
}
}


I use GeoFire to get keys for listings in a given radius. I then use observeSingleEventOfType to return the listing for the key. This all works fine.

However, I would like to only return a listing if the "ends" timestamp > current time. I have tried the following approach:

geoQueryHandle = geoQuery.observeEventType(.KeyEntered, withBlock: {(key, location) in

let listingRef = self.ref.child("listings").child(key)
let now = Int(NSDate().timeIntervalSince1970 * 1000)
let query = listingRef.queryStartingAtValue(now, childKey: "ends")

query.observeSingleEventOfType(.Value, withBlock: {snapshot in

if let listing = Listing(snapshot: snapshot, location: location) {
//...populate my tableview
}
}
})


Can anyone advise me on why my query isn't working?

Thanks

Answer

Firebase queries apply ordering/filtering to the properties of the child nodes of the location where you execute them.

queryLocation
  child1
    filterProperty: filterValue
  child2
    filterProperty: filterValue

Since your listingRef already points to a specific listing, the order/filter you add will apply to child nodes one level deeper.

The simplest way to get your use-case working seems to simply filter the node client-side:

let listingRef = self.ref.child("listings").child(key)

query.observeSingleEventOfType(.Value, withBlock: {snapshot in
    if let listing = Listing(snapshot: snapshot, location: location) {
        let now = Int(NSDate().timeIntervalSince1970 * 1000)
        // TODO: exit if snapshot.child("ends").getValue() < now
        //...populate my tableview
    }
}

A more complex, but more efficient, way to accomplish this would be to remove the expired events from the Geofire location.