How to Properly Use Queryorderedbyvalue

How to properly use queryOrderedByValue

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:

  • Firebase snapshot.key not returning actual key?
  • Firebase getting data in order
  • Firebase queryOrderedByChild() method not giving sorted data

How do you queryOrderedByValue on a key that is auto-generated in Swift?

Firebase Database queries run on each child node under the location where you run them, so they autoskip the third level under user-pings in your case.

You just need to specify what property to order/filter on, which seems to be active here. So something like:

REF_USERS_PINGS.child(currentUid).child(forId).queryOrdered(byChild: "active").queryEqual(toValue: "true").observeSingleEvent(of: .value) { (snapshot) in

Firebase queryOrderedByChild() method not giving sorted data

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.

firebase real time dB retrieving of specific data from multiple users in swift

You can:

  1. Load all JSON from /Users.
  2. Loop over snapshot.children.
  3. Then get the value of each child's username property.

These are also the most common navigation tactics when it comes to Firebase Realtime Database, so you'll apply these to pretty much any read operation.

Something like this:

Database.database().reference().child("isers").observe(.value, with: { (snapshot) in
if !snapshot.exists() {
print("No users found")
} else {
for case let userSnapshot as DataSnapshot in snapshot.children {
guard let dict = userSnapshot.value as? [String:Any] else {
print("Error")
return
}
let username = dict["username"] as? String
print(username)
}
}
})

Also see:

  • the documentation on reading data.
  • the documentation on listening for lists of data with a value event.
  • How to properly use queryOrderedByValue
  • Get Children of Children in Firebase Using Swift
  • And more from searching on [firebase-realtime-database][swift] children.

Firebase getting data in order

Solution: After very extensive searching and attempting, the problem still persisted that once the snapshot was converted to a snapVal (snapshot.value), the order often rearranged. My (working) solution:

for child in snapshot.children {
let child = child as! FIRDataSnapshot
if let childVal = child.value as? [String: AnyObject] {
let childMessage = childVal["MESSAGE"] as! String
// more code for each child. This child might be a post of a sort, which you can access properties of in a way like I did in the line above
}
}

Process:

  1. Loop through each child in snapshot

  2. Convert the child to a FIRDataSnapshot so it is not an element

  3. Get the value of the particular child to access properties from

  4. Add in the respective code for the child following NSDictionary principles.

Why this solution is solid

Receiving snapshots in the proper order is very simple. The issue I faced was getting data in the correct order when I got the snapshot.value. This solution fixes that because the values of each child are only accessed when looping through the children of snapshot, which is sorted. This leaves the order of children still in the control of the snapshot.

I also like the snapshot.value approach by using [String: AnyObject] because it is very close to the old functionality of Firebase implementation in Swift: Simple and very clean. I actually think that using NSDictionary in this way is really a way to save time in the long run because it is not verbose in any way.

Swift4 Firebase database sorting not working

Most likely you're calling snap.value, which returns the child nodes in a dictionary. And the entries in a dictionary are by definition unordered.

To get the results in the order that you queried them in, you need to iterate over snap.children.

See my answer here for an example: How to properly use queryOrderedByValue

Firebase snapshot.key not returning actual key?

When you run a query at a location, the result will be a list of the matching children. Even if there is only a single matching item, the result will be a list of one child.

You're printing the key of all resulting children. Since there is no single result, the SDK prints the key of the location/collection that you queried: users.

What you're likely looking for is to loop over the matching children and print their keys:

let query = usersRef.queryOrderedByChild("email").queryEqualToValue(email)
query.observeEventType(.Value, withBlock: { snapshot in
for child in snapshot.children {
print(child.key)
}
})

Query Firebase Data From Different Nodes

Figured that I need a news feed node for each user. This is a good read if you are running into the same problem.

https://firebase.googleblog.com/2015/10/client-side-fan-out-for-data-consistency_73.html

iOS Firebase Paginate by Date

Firebase queries can only order/filter on a value that is (in a fixed path) under the node that it's considering to return. So you can't posts-userIds on values from under posts.

The solution is to duplicate the value that you want to order/filter on under posts-userIds, either directly as the value (in which case you'll use queryOrderedByValue for the order), or in a child property (in which case you'll use queryOrdered(byChild:) for the order. I tend to favor the latter, simply because once there's one value you want to order/filter on, there'll often be more of them down the line.

This sort of data duplicating is quite common in NoSQL databases, so if you're not yet comfortable with it, I recommend reading NoSQL data modeling, and watching Firebase for SQL developers.



Related Topics



Leave a reply



Submit