ilvcs ilvcs - 3 months ago 47
Swift Question

Firebase queryOrderedByChild() method not giving sorted data

Hi my database structure is some thing like this

{
"users": {
"alovelace": {
"name": "Ada Lovelace",
"score": 4,
},
"ghopper": { ... },
"eclarke": { ... }
}
}


I am trying to retrieve top 20 scores in descending order.

let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToLast(20)
queryRef.observeSingleEventOfType(.Value, withBlock: { (quearySnapShot) in
print(quearySnapShot.value)
})


i am trying to get output like

score": 4
score": 3
score": 2

or

score": 2
score": 3
score": 4

or

2
3
4


Please let me know how to solve this.

Answer

When you request the children in a specific order, the resulting snapshot will contain both the data that matches the query and information about the order in which you requested them.

But when you request the .value of the snapshot, the keys+data are converted to a Dictionary<String,AnyObject>. Since a dictionary does not have an extra place to put the information about the order, that information is lost when converting to a dictionary.

The solution is to not convert to a dictionary prematurely and instead loop over the snapshot:

queryRef.observeSingleEventOfType(.Value, withBlock: { (querySnapShot) in
    for childSnapshot in querySnapShot.children {
        print(childSnapshot.value)
    }
})

You can also listen to the .ChildAdded event, instead of .Value, in which case the children will arrive in the correct value:

queryRef.observeSingleEventOfType(.ChildAdded, withBlock: { (childSnapshot) in
    print(childSnapshot.value)
})

Update

I just added this JSON to my database:

{
  "users" : {
    "alovelace" : {
      "name" : "Ada Lovelace",
      "score" : 4
    },
    "eclarke" : {
      "name" : "Emily Clarke",
      "score" : 5
    },
    "ghopper" : {
      "name" : "Grace Hopper",
      "score" : 2
    }
  }
}

And then ran this code:

let queryRef = ref.child("users").queryOrderedByChild("score").queryLimitedToLast(20);
queryRef.observeEventType(.ChildAdded) { (snapshot) in
    print(snapshot.key)
}

The output is:

ghopper

alovelace

eclarke

Which is the users in ascending order of score.

Update to add more on getting the scores in descending order

The above code gets the 20 highest scores in ascending order. There is no API call to return themthem in descending score.

But reversing 20 items client side is no performance concern, you just need to write the code for it. See for example this answer.

If you really are stuck on reversing them client side, you can add an inverted score. See this answer for an example of that.

Comments