0

My app has a collection view which displays rows of photos/images from Firebase, and I'd like to have them load in the order they were added, with the newest posts at the top. I thought that using queryOrderedByKey did that by default, and that's what I used in my fetch function, but the posts are out of order.

This is how I'm fetching the posts currently:

func fetchPosts() {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in

        let users = snapshot.value as! [String : AnyObject]

        for (_, value) in users {

            if let uid = value["uid"] as? String {

                if uid == FIRAuth.auth()?.currentUser?.uid {

                    if let followingUsers = value["following"] as? [String : String] {

                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

                    ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
                        let postsSnap = snap.value as! [String : AnyObject]

                        for (_, post) in postsSnap {
                            if let userID = post["userID"] as? String {
                                for each in self.following {
                                    if each == userID {

                                        let posst = Post()
                                        if let poster = post["poster"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {

                                            posst.poster = poster
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            if let people = post["peopleWhoLike"] as? [String : AnyObject] {
                                                for (_, person) in people {
                                                    posst.peopleWhoLike.append(person as! String)
                                                }
                                            }
                                            posts.append(posst)
                                        }
                                    }
                                }
                                self.collectionView.reloadData()
                            }
                        }
                    })
                    ref.removeAllObservers()
                }
            }
        }
    })
}

How can I get the posts to sort by newest first?

EDIT 2: updated - now sorting from oldest -> newest

func fetchPosts() {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in

        let users = snapshot.value as! [String : AnyObject]

        for (_, value) in users {

            if let uid = value["uid"] as? String {

                if uid == FIRAuth.auth()?.currentUser?.uid {

                    if let followingUsers = value["following"] as? [String : String] {

                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

                    ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in

                        for postSnapshot in snap.children.allObjects as! [FIRDataSnapshot] {
                            let value = postSnapshot.value as! [String : AnyObject]

                            if let userID = value["userID"] as? String {
                                for each in self.following {
                                    if each == userID {

                                        let posst = Post()
                                        if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String {

                                            posst.poster = poster
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            if let people = value["peopleWhoLike"] as? [String : AnyObject] {
                                                for (_, person) in people {
                                                    posst.peopleWhoLike.append(person as! String)
                                                }
                                            }
                                            posts.append(posst)
                                        }
                                    }
                                }
                                self.collectionView.reloadData()
                            }
                        }
                    })
                    ref.removeAllObservers()
                }
            }
        }
    })
}
KingTim
  • 1,281
  • 4
  • 21
  • 29

1 Answers1

2

Queries return a snapshot the matching child nodes in the order requested. That means that the results consists of three things:

  1. the item keys
  2. the item values
  3. the order of the items relative to each other

But then the first thing you do with the snapshot is:

ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
  let postsSnap = snap.value as! [String : AnyObject]

You convert the snapshot into a dictionary. And a dictionary only has space for two things: the keys and the values. So the order is lost at this point, since dictionaries have an undefined order.

The proper way to access the result in the order you requested is to use the snapshot's built-in collection of children to iterate over them:

ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in

  for postSnapshot in snapshot.children {
    let value = postSnapshot.value as! [String : AnyObject]

This will loop over the matching children in the order you queries them.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks! When trying to do it this way, Xcode throws me an error and suggests changing `let value = postSnapshot.value as! [String : AnyObject]` to `let value = (postSnapshot as AnyObject).value as! [String : AnyObject]`, which then gives me another error, "ambiguous use of `value`" – KingTim Mar 19 '17 at 14:51
  • http://stackoverflow.com/questions/27341888/iterate-over-snapshot-children-in-swift-firebase – Frank van Puffelen Mar 19 '17 at 14:56
  • Thanks for the link, I changed my code (I edited my question to add the updated code) and now the posts are sorted from oldest to newest, any idea how I can switch that around? I tried adding `.reversed()` after `allObjects` but I got a warning, then a crash upon running. – KingTim Mar 20 '17 at 13:21