2

I have this function written in Swift that fetch the leaderboard and then shows it to the user :

@IBAction func onShowLeaderboardTapped(_ sender: Any) {
        let leaderboardDB = FIRDatabase.database().reference().child("scores").queryOrderedByValue().queryLimited(toLast: 5)

        leaderboardDB.observeSingleEvent(of: .value, with: { (snapshot) in
            print("leaderboard snapshot:" ,snapshot)
        }, withCancel: nil)

    }

The problem is that when I fetch it, it gaves me the following list :

 Ben = 9;
 Gabriela = 12;
 Ivailo = 7;
 Petar = 10;
 Vania = 10;

It shows me the first five players, but then it lists them alphabetically. Since this is not a big problem I wonder if there is a way to order them by the value.

These are the rules:

{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null",
      "scores": {
      ".indexOn": ".value"
    }
  }
}

And the DB is organized as follows:

  matchrooms:
  users: 
  scores:
>      Ben: 9
>      Dimitar: 7
>      Gabriela: 12
>      Ishest: 6
>      Ivailo: 7
>      Ivan: 5
>      Marina: 3
>      Pesho: 3
>      Petar: 10
>      Rosen: 6
>      Vania: 10
>      Yasen: 2

So, my question is how to properly use the queryOrderedByValue() to retrieve the first five players and list them by the points they've scored?

i6x86
  • 1,557
  • 6
  • 23
  • 42
John Smith Optional
  • 431
  • 2
  • 4
  • 18
  • So first off - this is a bad way to structure your firebase data, you should have a node name generated by childByAutoId, with child nodes of name: some name and score: some score. Then you can query those nodes and sort by name or score etc. As it is, you are sorting byValue which is exactly what you are getting - B)en, G)abriela, I)vailo (B, G, I, P V). – Jay Nov 29 '16 at 21:17
  • i know it's a bad way, if you noticed, i have users node where they are registered with the childByAutoId func. the list i generated is just to play around with firebase. – John Smith Optional Nov 30 '16 at 17:04

2 Answers2

8

When you fire a query against Firebase, it returns the keys of the items that match your query, the value of those items and the relative order of the items in the result. If you listen for a .Value event, all three of these are combined into a single FIRDataSnapshot.

But when you then either ask for the value property of that snapshot or print that snapshot as one block, the data is converted into a Dictionary. Since a dictionary can only contain keys and values, the ordering of the items is lost at that point. And as it turns out, the dictionary then prints the items ordered by their key.

To get the items in order, you should iterate over them using snapshot.children:

leaderboardDB.observeSingleEvent(of: .value, with: { (snapshot) in
    for child in snapshot.children {
        print(child.key)
    }
}, withCancel: nil)

Also see:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 1
    thank you, it helps me, I have to use snap.value. now I had tried "snap.children" which works fine. In a same query snap.value return unsorted data snap.children return sorted data – RiTeSh Mar 31 '20 at 15:59
0

Change the structure

scores
  -YUijia099sma
    name: "Ben"
    score: 9
  -Yij9a9jsddd
    name: "Dimitar"
    score: 7

then

@IBAction func onShowLeaderboardTapped(_ sender: Any) {
        let leaderboardDB = FIRDatabase.database().reference().child("scores")
                           .queryOrdered(byChild: "score")
                           .queryLimited(toLast: 5)

        leaderboardDB.observeSingleEvent(of: .value, with: { (snapshot) in
            print("leaderboard snapshot:" ,snapshot)
        }, withCancel: nil)

    }

*typing on my iPad so it's not tested and the syntax may not be perfect

Jay
  • 34,438
  • 18
  • 52
  • 81