beginner_T
beginner_T

Reputation: 427

Firebase snapshots in wrong order

I try to load the posts I stored on firebase into my tableView. I used the .childAdded function to get the post in the order they have been posted (first to last). First it seemed to work, but now it doesn't work no more and I don't know why. So I added a timestamp to the posts and used queryOrderedByChild("timestamp"). Still the wrong order though! Here is my code:

posts.removeAll()
    let ref = FIRDatabase.database().reference()

    ref.child("Posts").queryOrderedByChild("timestamp").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in

        print(snapshot.value!["timestamp"] as! Int)
        if snapshot.value == nil {
            return
        }
        let post = Post()
        post.title = snapshot.value!["Title"] as? String
        post.postType = snapshot.value!["postType"] as? Int
        post.postDescription = snapshot.value!["Description"] as? String

        if post.postType == 2 {
            post.imageAURL = snapshot.value!["imageAURL"] as? String
            post.imageBURL = snapshot.value!["imageBURL"] as? String
        }else if post.postType == 3 {
            post.imageAURL = snapshot.value!["imageAURL"] as? String
            post.imageBURL = snapshot.value!["imageBURL"] as? String
            post.imageCURL = snapshot.value!["imageCURL"] as? String
        }


        let createdByID = snapshot.value!["createdBy"] as! String
        var username = String()
        let usernameRef = FIRDatabase.database().reference().child("users").child(createdByID)
        usernameRef.observeSingleEventOfType(.Value, withBlock: { (snapshot:FIRDataSnapshot) in

            username = snapshot.value!["username"] as! String
            post.createdBy = username
            self.posts.append(post)
            self.tableView.reloadData()
            }, withCancelBlock: nil)




            dispatch_async(dispatch_get_main_queue(), {

                self.tableView.reloadData()
            })


        }, withCancelBlock: nil)


}

the print of the timestamp value in the beginning of the query puts out:

1471008028
1471007899
1471007928
1471007979

As you can see, the first Int is the highest, the next three are ordered correctly in ascending order, but why is the highest first and not last? I don't know if it has anything to do with it, but the code is inside a function that is called inside viewDidLoad.

Upvotes: 2

Views: 1744

Answers (1)

cartant
cartant

Reputation: 58440

There is an existing answer that explains why Firebase JavaScript child_added events occur out-of-order. It is still applicable and is the reason why your snapshots are being delivered in an unexpected order.

I know this may seem strange, but this is actually the intended behavior.

In order to guarantee that local events can fire immediately without communicating with the server first, Firebase makes no guarantees that child_added events will always be called in sort order.

To arrange the received snapshots into the correct order, you need the previous sibling key that accompanies the snapshot (it's referred to as the prevChildName in the referenced answer). To obtain the previous sibling key, you need to use observeEventType:andPreviousSiblingKeyWithBlock:.

The Firebase documentation for observeEventType:andPreviousSiblingKeyWithBlock: does not make it clear how the previous sibling key ought to be used to arrange the received snapshots.

For the purposes of an example, to store and order the snapshots in an array, you would need to do the following for each received a snapshot:

  • if the received snapshot has a null previous sibling key, add it to the head of the array;
  • otherwise, find the snapshot in the array that has a key equal to the previous sibling key (that accompanied the recieved snapshot) and insert the received snapshot into the array after the found snapshot;
  • if there is no snapshot with the previous sibling key, add the received snapshot to the tail of the array.

Upvotes: 1

Related Questions