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: { (querySnapShot) in
print(querySnapShot.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.
Use method observeEventType
instead of observeSingleEventOfType
.
Also, make FIRDataEventType to ChildAdded
.
Last, If you want Top 20 items, use queryLimitedToFirst
instead of queryLimitedToLast
.
{
"users" : {
"alovelace" : {
"name" : "Ada Lovelace",
"score" : 4
},
"eclarke" : {
"name" : "Emily Clarke",
"score" : 5
},
"ghopper" : {
"name" : "Grace Hopper",
"score" : 2
}
}
}
For the dataset above
let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToFirst(20)
queryRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
print("key: \(snapshot.key), value: \(snapshot.value)")
})
key: ghopper, value: Optional({
name = Grace Hopper;
score = 2;
})
key: alovelace, value: Optional({
name = Ada Lovelace;
score = 4;
})
key: eclarke, value: Optional({
name = Emily Clarke;
score = 5;
})
Snapshot will returns the contents as native types.
Data types returned:
- NSDictionary
- NSArray
- NSNumber (also includes booleans)
- NSString
So, you can get your scores this way.
let queryRef = FIRDatabase.database().reference().child("users").queryOrderedByChild("score").queryLimitedToFirst(20)
queryRef.observeEventType(.ChildAdded, withBlock: { (snapshot) in
if let scores = snapshot.value as? NSDictionary {
print(scores["score"])
}
})
Optional(2)
Optional(4)
Optional(5)
Moreover, the default of realtime database return everything in ascending order.
If you want descending order, you can make some tricks(4:40) in your database.
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.