Firebase sorting clarification on snapshot.value - ios

Was hoping someone could help me understand Firebase snapshot and sorting. Why if you queryOrderedByChild on a FirebaseDBRef, the snapshot.value returns as displayed on the Firebase Database (using the browser), but if you do for snap in snapshot.children{} the values do show sorted. Just wanting clarification on why this happens.
Let me explain with example.
let dinoRef = rootRef.child("dino")
let query = dinoRef.queryOrderedByChild("dimensions/height")
query.observeSingleEventOfType(.Value, withBlock: { snapshot in
// This prints to the console unsorted
print(snapshot.value)
// This prints to console sorted
for snap in snapshot.children {
print(snap)
}
})
Thank you.

A FIRDataSnapshot contains information about the keys of the returns data, the values associated with those keys and the order of the keys. When you call snapshot.children the snapshot the enumerator will return the children in the order you requested.
When you call snapshot.value on a snapshot, it must convert all the information to an NSDictionary. A dictionary has no inherent information on the order of data, so the order of the results is lost at this point.

You must try order by child with ascending and descending option. That will clarify your doubt.

Related

Firebase retrieving child nested data

I want to retrieve data on with this value 7hmpcTuCAYQAYRqP7RNmnegSd9r2
But i'm getting all four objects in snapshot. I want to get parent key values which contain this key
7hmpcTuCAYQAYRqP7RNmnegSd9r2
Need to get blue mark keys.
Here is my code
let ref = FirebaseManager.refs.databaseRoot.child("new_ChatListMembers")
ref.queryOrdered(byChild: (Auth.auth().currentUser?.uid)!).queryEqual(toValue: true)
ref.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
}
This code return four objects instead of two.Please help me how i can get specific data.
Thanks
You're not actually using the query that you construct in your code. To use that, it'd be something like:
let ref = FirebaseManager.refs.databaseRoot.child("new_ChatListMembers")
let query = ref.queryOrdered(byChild: (Auth.auth().currentUser?.uid)!).queryEqual(toValue: true)
query.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
}
But this won't actually scale very well, as you'll need to define an index for each individual UID value in this structure. In short: your current data structure makes it each to find the users for a specific chat room, but it doesn't help finding the chat rooms for a specific user.
To allow the latter, you'll want to add an extra structure in your data:
user_chats: {
"$uid": {
"$chatid": true
}
}
So this is pretty much the inverse of what you have already, which is why this is often called an inverse index.
For more on this, and another example, see my answer here: Firebase query if child of child contains a value

How to loop through Firebase data

How to loop through Firebase data (childs) which are actually objects and access to their properties in Swift 4?
As a beginner with Swift, I am trying to loop through data I am retrieving from Firebase, and I am trying to access to properties of those objects. Seems much more complicated then it should be in swift (just my subjective opinion)
As per documentation on the Firebase site this is what I have
_commentsRef.observe(.value) { snapshot in
for child in snapshot.children {
// Access to childs here ...
}
}
Now, combining this above and as per tutorials and explanations (btw was not able to find neither one which explains this fully) which I found on net, this is what I have:
ref.child("activities").child("list").observeSingleEvent(of: .value, with: { (snapshot) in
// The list i got here is the list of the childs which are objects
// Lets loop through that list and pull properties we need
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.value)
}
})
The print in the loop will properly display object with all of its properties, but I am not able to access to these properties. Accessing to it with something like "child.value.title" is resulting with error "Value of type 'Any' has no member 'title'"
Do I need to convert child.value to something else, maybe to cast it or to convert it somehow to property accessible JSON or something like that?
If you call value on a snapshot that contains multiple properties, what you get back is a NSDictionary with the property names as the keys. So to get the value of the title key you'd do:
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.value)
let dict = child.value as? [String : AnyObject] ?? [:]
print(dict["title"])
}
Alternatively you can use the other members of DataSnapshot to navigate to the title property and then call .value on that:
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.value)
print(child.childSnapshot(forPath: "title").value)
}
See DataSnapshot.value and the first sample in the Firebase documentation on reading data.

How to Sort Firebase SnapShot by inner Child

I have dictionaries in Firebase real-time database. I need to sort the entire dictionaries with an inner child in the dictionary.
I need to query the sort, using timestamp child.
self.ref?.child(FirebaseConstants.main.dbBase).child(getRoom(forUser: id)).queryOrdered(byChild: "timeStamp").observe(.value, with: { (snapShot) in
print(snapShot)
})
I tried this not working.
Since we don't know the value of the variables, it's hard to say precise. But say this structure is under /messages/10_22 then you can query it with:
Database.database().reference("messages/10_22").queryOrdered(byChild: "timeStamp").observe(.value, with: { (snapShot) in
println(snapshot.childrenCount)
for message in snapshot.children.allObjects as [FIRDataSnapshot] {
println(message.key+": "+message.value)
}
})

Snapshot returned from Firebase database event childChanged on iOS

In my app I fetch data from Firebase when a node is changed:
handle = ref?.child("orders").child("4").observe(.childChanged, with: { (snapshot) in
if snapshot.key == "price" {
print("price: \(snapshot.value)")
}
if snapshot.key == "orders" {
print("orders: \(snapshot.value)")
}
}, withCancel: nil)
But is the above function really the way to do it?
I have tried to setup a if statement to check what values is being return then grab that value from snapshot.value but I am worried if I change all my values at once I can't tell from what node snapshot.value is coming from.
Yes, for tracking children nodes changes that's the way to do it!
Firebase documentation, for the corresponding childChanges database event, provides further details:
Listen for changes to the items in a list. This event is triggered any time a child node is modified. This includes any modifications to descendants of the child node. The FIRDataSnapshot passed to the event listener contains the updated data for the child.
As such, snapshot.key identifies the updated child node and snapshot.value the corresponding data.

Storing children of Firebase Database in an array

I have set up a Firebase database that has a parent and many different children. I am attempting to save all of the children's keys into an array that I can access elsewhere in the code.
// Used to get the children
rootRef.child(partyName).observe(.childAdded, with: { (snapshot) in
var newItems = [FIRDataSnapshot]()
for item in snapshot.children {
newItems.append(item as! FIRDataSnapshot)
}
if let snapDict = snapshot.value as? [String:AnyObject]{
for each in snapDict{
let keyID = each.key
saves.append(keyID)
}
}
})
Unfortunately, most of the "solutions" that I have found online simply print the retrieved data or add it to a Table View. I simply want all the children to be saved in an array that I can access later. Is this possible? If so, how would I do it?
Thanks
The proper way of storing the retrieved data is to store the key-value pairs in an NSDictionary or a Swift Dictionary. As Sachin Vas said, it makes no sense to store just the keys because then you'd have no relation back to the values.
Nevertheless, to answer your question, the code you provided in your question does what you're asking. If saves is a global or static array in some class, it would be accessible globally throughout your application and would contain all the retrieved keys.
The right way of storing the retrieved data would work just the same way, except saves would be a Dictionary.
rootRef.child(partyName).observe(.childAdded, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject] {
saves = snapDict // where saves is declared as Dictionary<String, AnyObject>
}
})

Resources