Abcdefg Abcdefg - 5 months ago 71
Swift Question

Firebase query to only return new posts?

I'm fairly new with firebase so my lack of code isn't a lack of trying more of a just "I dont really know where to begin here".

I'm trying to only show posts that are 10 minutes "old" or less. I'm going to run a timer in my app to send the query every second (assuming this doesn't cause too much of an issue?) to check to make sure the current posts aren't over that 10 minute mark, and if they are, the query just shouldn't return them.

I've got it set up where when the user makes a post a timestamp is created.

The setup is :

Posts
02983094jfksdflkaj3l
timestamp: 23478923019


I'm assuming I need to orderByValue? to sort the posts by the timestamp and then return it with a limit of some sort, but I'm not sure how to map all of that out.

A point in the right direction would be greatly appreciated here.

Thanks in advance!

edit: I'm no longer getting any posts appearing in the collectionview...and no matter how many posts I have that should satisfy the under 10 minute query, only one ever returns.

Like I show below, I'm not getting a .value return on the snap...which should return the timestamp value I get shown in the timestamp snap print, no?

override func viewWillAppear(animated: Bool) {
let cutoff = UInt64(1000 * floor(NSDate().timeIntervalSince1970) - 10*60*1000);
let cutoffFloat = Float(cutoff) // <-- woudnlt take a UInt64 as an AnyObject. I assume its ok to just do this?


DataService.ds.REF_POSTS.queryOrderedByChild("timestamp").queryStartingAtValue(cutoffFloat).observeSingleEventOfType(.ChildAdded) { (snapshot: FIRDataSnapshot) in
print("child added") // <------- isn't ever getting called
self.Posts = []
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {

for snap in snapshots {

print("timestamp snap: \(snap)") // <---- returns timestamp snap: Snap (timestamp) 23904819242

if let postDict = snap.value as? Dictionary<String, AnyObject> {

print(snap.value)// <----- Returns nothing
let key = snap.key
let post = Post(postKey: key, dictionary: postDict)
self.Posts.append(post)

}
}
}

self.collectionView.reloadData()


}

I don't know if it's any help but here was my code I was using before to populate the collection view:

DataService.ds.REF_POSTS.observeEventType(.Value) { (snapshot: FIRDataSnapshot) in

self.Posts = []
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {

for snap in snapshots {

print(snap)

if let postDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let post = Post(postKey: key, dictionary: postDict)
self.Posts.append(post)
}
}
}

print("got here")
self.collectionView.reloadData()


}

Answer

Running a timer and sending a different query every 10 seconds is a horrible use of a realtime database. Instead run the query once asking for all posts since 10 minutes ago and keep that query active.

Borrowing from @JustinM's code:

let ref = FIRDatabase.database().reference
let cutoff = UInt64(1000 * floor(NSDate().timeIntervalSince1970) - 10*60*1000);    
ref.child("post")
   .queryOrderedByChild("timestamp")
   .queryStartingAtValue(cutoff)
   .observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
       let post = Post(title: snapshot["title"], timestamp: snapshot["timestamp"])
       self.postsArray.append(post)
   }

   self.tableView.reloadData()

    // start a timer that removes expired items from postsArray
    NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "removeExpiredItems", userInfo: nil, repeats: true)
})

Then client-side run your timer and discard the posts as they "expire".

func removeExpiredItems() {
    let cutoff = UInt64(1000 * floor(NSDate().timeIntervalSince1970) - 10*60*1000)
    while (self.postsArray.count > 0 && self.postsArray[0].timestamp < cutoff) {
        // remove first item, because it expired
        self.postsArray.removeAtIndex(0)
    }
    self.tableView.reloadData()
}
Comments