3

When I load the following Firebase Database data into my tableView, the data is sorted in ascending order by date. How can I order this by descending (show the newest post at the top)?

Query in Xcode:

let ref = self.rootRef.child("posts").queryOrderedByChild("date").observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in

JSON export:

"posts" : {
    "-KMFYKt7rmfZINetx1hF" : {
      "date" : "07/09/16 12:46 PM",
      "postedBy" : "sJUCytVIWmX7CgmrypqNai8vGBg2",
      "status" : "test"
    },
    "-KMFYZeJmgvmnqZ4OhT_" : {
      "date" : "07/09/16 12:47 PM",
      "postedBy" : "sJUCytVIWmX7CgmrypqNai8vGBg2",
      "status" : "test"
    },

Thanks!!

EDIT: Below code is the entire solution thanks to Bawpotter

Updated query:

let ref = self.rootRef.child("posts").queryOrderedByChild("date").observeEventType(.ChildAdded, withBlock: { (snapshot) -> Void in

    let post = Post.init(key: snapshot.key, date: snapshot.value!["date"] as! String, postedBy: snapshot.value!["postedBy"] as! String, status: snapshot.value!["status"] as! String)

    self.posts.append(post)

    self.tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: self.posts.count-1, inSection: 0)], withRowAnimation: .Automatic)

tableView cellForRowAtIndexPath

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("PostCell", forIndexPath: indexPath) as! PostCell

        self.posts.sortInPlace({$0.date > $1.date})
        self.tableView.reloadData()

Post.swift:

import UIKit

class Post {
    var key: String
    var date: String
    var postedBy: String
    var status: String

    init(key: String, date: String, postedBy: String, status: String){
        self.key = key
        self.date = date
        self.postedBy = postedBy
        self.status = status
    }
}
winston
  • 3,000
  • 11
  • 44
  • 75

4 Answers4

12

When Firebase loads the data into your tableView data source array, call this:

yourDataArray.sortInPlace({$0.date > $1.date})

Swift 3 Version:

yourDataArray.sort({$0.date > $1.date})

Swift 4 Version:

yourDataArray.sort(by: {$0.date > $1.date})
Marc Hampson
  • 257
  • 1
  • 4
  • 17
Bryan
  • 1,335
  • 1
  • 16
  • 32
  • Thanks for the reply! I get error `Value of type 'FIRDataSnapshot' has no member 'date'`. Updated my code – winston Aug 04 '16 at 02:10
  • Ah okay. Here's what I'd recommend. Create a new custom class (should take no more than 5 minutes) called Post, with the properties "date", "postedBy", and "status". Your self.posts array will become an array of Post objects, and then you'll have no problem sorting the array. While it may seem like a lot of work to go through, having a custom class associated with your Firebase data objects will make your life MUCH easier, especially down the road. – Bryan Aug 04 '16 at 02:20
  • I updated the question with my new Post class. I used some example code from the Firebase docs as a reference. How can I now point my self.posts array to look at that new class? – winston Aug 05 '16 at 12:46
  • So at this point your self.posts array is still an array of FIRDataSnapshots. Your property declaration for self.posts should be `var posts: Array`. Now, when you get a new post from Firebase, you create a new Post object with the info from Firebase. Add THAT to the array, and then you'll be able to easily sort your array. The key is making sure that your array is of Post objects, not of FIRDataSnapshots. – Bryan Aug 05 '16 at 15:04
  • Got it! It took me a while to figure out how to make the class and populate an instance of the class using the snapshot data but it works! Thanks for taking the time to explain the solution. – winston Aug 05 '16 at 20:54
  • Quick question: the data doesn't load in the correct sort order until I scroll to the end of the table. Then if I scroll back to the top, the data is in the right sort order. Do I need to place the sortInPlace method somewhere else? Thanks! – winston Aug 05 '16 at 21:11
  • I would put it right after you finish loading your Firebase data. And glad I could help! – Bryan Aug 05 '16 at 21:46
  • Had in the right place but I needed to add `self.tableView.reloadData()`. Works fine now. Thanks again!! – winston Aug 05 '16 at 23:26
  • if you do a sort every time you need a cell, showing a cell will get very slow as the number of items increase. – Mick F Jan 19 '17 at 17:56
  • @Bawpotter Can you please help me on my question https://stackoverflow.com/questions/61026927/how-to-sort-firebase-order-to-ascending-using-querysnapshot-in-swift – Muju Apr 04 '20 at 11:29
  • Surely this will only work if you have a small list of elements? – user11145365 Apr 13 '20 at 20:02
1

While I do recommend doing what was posted and creating a Class and doing it that way, I will give you another way to do sort it.

Since you already have it sorted in Ascending order from Firebase and you know the amount of records, you can do this:

guard let value = snapshot.children.allObjects as? [FIRDataSnapshot] else {
                    return
}
var valueSorted: [FIRDataSnapshot] = [FIRDataSnapshot]()
var i: Int = value.count
while i > 0 {
    i = i - 1
    valueSorted.append(value[i])
}
Joe
  • 157
  • 1
  • 12
1

Simply use .reverse() before using data

Example:

myRef.observe(.value) { (snapshot) in
    guard var objects = snapshot.children.allObjects as? [DataSnapshot] else {
        return
    }
    
    objects.reverse() //<========= HERE
    
    //Now use your `objects`
    ...
}
Community
  • 1
  • 1
Husam
  • 8,149
  • 3
  • 38
  • 45
0

Swift 5: Add reversed() to your objects after sorting by the required field. For example, let's assume you have a day of the month in the "day" field in FireStore. Something like this will do the trick (call loadData() function in viewDidLoad to see the output):

let db = Firestore.firestore()
func loadData() {
        db.collection("FireStoreCollectionName").order(by: "day").getDocuments { (querySnapshot, error) in
            if let e = error {
                print("There was an issue retrieving data from Firestore, \(e)")
            } else {
                for document in querySnapshot!.documents.reversed() {
                    let data = document.data()
                    let fDay = data["day"] as! Int
                    print(fDay)                                       
                }
            }
        }
    }
Michael
  • 40
  • 4