winston
winston

Reputation: 3100

Firebase query sort order in swift?

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
    }
}

Upvotes: 3

Views: 13743

Answers (4)

Michael
Michael

Reputation: 56

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)                                       
                }
            }
        }
    }

Upvotes: 0

Husam
Husam

Reputation: 8568

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`
    ...
}

Upvotes: 2

Bryan
Bryan

Reputation: 1365

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})

Upvotes: 12

Joe
Joe

Reputation: 157

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])
}

Upvotes: 1

Related Questions