Jeffrey Chang
Jeffrey Chang

Reputation: 433

Firebase query ordering by child not working properly

Problem

I'm trying to query a list of objects by createionDate. For some reason it will not fetch objects in a ascending order.

My data structure

enter image description here

my code

func fetchQuest() {
        
        guard let uid = selectedUID else {return}
        
        let ref = FIRDatabase.database().reference().child("questsByUID").child(uid)
        let query = ref.queryOrdered(byChild: "CreationDate")
        query.observeSingleEvent(of: .value, with: { (snapshot) in
            
            
            guard let dictionaries = snapshot.value as? [String: Any] else {return}
            dictionaries.forEach({ (key, value) in
                
                guard let dictionary = value as? [String : Any] else {return}
                let quest = Quest(uid: uid, dictionary: dictionary)
                quest.questID = key
                print("quest name is: ", quest.questName)
                self.board.append(quest)
                
            })
            self.collectionView?.reloadData()
        }) { (err) in
            print("unable to fetch quest:", err)
        }
    }

My Model

class Quest {

var questID = ""
let questName: String
let creatorUID: String
let creationDate: Date

init(uid: String, dictionary: [String: Any]) {
    self.questName = dictionary["questName"] as? String ?? ""
    self.creatorUID = uid
    let secondsFrom1970 = dictionary["creationDate"] as? Double ?? 0
    self.creationDate = Date(timeIntervalSince1970: secondsFrom1970)
}}

console output

quest name is: Third quest

quest name is: 2nd quest

quest name is: 4th quest from Ada

quest name is: Ada’s first quest

Upvotes: 2

Views: 2503

Answers (2)

Paulo Mattos
Paulo Mattos

Reputation: 19339

Given that the Firebase database is case sensitive, try changing your query from:

let query = ref.queryOrdered(byChild: "CreationDate")

to:

let query = ref.queryOrdered(byChild: "creationDate")

Your Quest model class is already using the correct spelling.

Update. As mentioned by the other answer, a dictionary is not order preserving. As such, you should be using FIRDataSnapshot.children iterator instead. For instance:

query.observeSingleEvent(of: .value) { 
    (snapshots) in
    for child in snapshots.children {
        let snapshot = child as! DataSnapshot
        guard let dictionary = snapshot.value as? [String : Any] else { return }
        let quest = Quest(uid: uid, dictionary: dictionary)
        quest.questID = snapshot.key
        ...
    }
}

Please note that I'm still using the same observeSingleEvent as your original code does.

Upvotes: 3

3stud1ant3
3stud1ant3

Reputation: 3606

I think order is different because dictionary is an unordered collection of key-value pairs. So I think since you want to get the values in ordered manner, you can use eventType of .childAdded because according to documentation :

Unlike value which returns the entire contents of the location, childAdded is triggered once for each existing child and then again every time a new child is added to the specified path

so you can modify your code like this:

  1. First as the other answer states that change CreationDate to creationDate

  2. Second use .childAdded instead of .value as the event type.

let query = ref.queryOrdered(byChild: "creationDate") query.observe(.childAdded, with: { (snapshot) in...

Upvotes: 1

Related Questions