Dictionary Changes Index Positions with .keys -- Swift - swift

I'm currently retrieving data from a firebase database, and storing the data in a dictionary. When I try to list the keys in the dictionary like this: snapDict?.keys the indexes of the elements aren't the same as how they are in the database.
Database.database().reference().child("\(UserData().mySchool!)/posts").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
let snapDict = snapshot.value as? [String: Any]
print(snapshot.value!)
let names = snapDict?.keys
print(names!)
for id in names! {
self.searchNames(id: id)
self.tableView.reloadData()
}
})
This is what the elements that will be in the dictionary look like in the database:
So, you would think when they are put into the dictionary they would be printed as -LJRUC8n........-LOF6JUdm-onVuaq-zij?
snapDict?.keys
prints:
["-LOBSAv_l5_x1xnKwx3_", "-LJRUC8nPF3Vg-DDGiYQ", "-LOBLXpTs39yLZo6EnHl", "-LOF6JUdm-onVuaq-zij", "-LODhXPQi8G7MX1bSfeb", "-LJaUiEnGOcBjKsTWSCS", "-LOBLZzrLAlzkhoidnKf"]
I can't figure out the order/pattern here. Alphabetical? Any ideas why the order turns out this way?

The keys in a dictionary are by definition unordered. So when you convert the snapshot to a dictionary, any information on the order of the nodes is lost.
On top of that, you don't specify an order before reading the data.
To fix both:
Database.database().reference()
.child("\(UserData().mySchool!)/posts")
.queryOrderedByKey()
.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
print(child.value)
}
})

Related

How to read values of a child from Firebase Realtime DB?

I am trying to get values from my database. However, I am unsuccessful. Here is what the DB looks like:
Here is what I tried to do, to read the values:
taskRef = Database.database().reference(withPath: "Tasks").child(titleOfTask)
taskRef?.observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let taskDict = snapshot.value as? [String:Any] {
print("Printing ---------> ",taskDict["Description"] as Any)
}
})
but nothing happens. Ideally, I want to read both the description in a different variable and due date into a different variable.
Important Things to know:
"Tasks" is.. you can think of it as a table name.
Alpha, Bravo, Jalabi... etc are all "Task Names" or childs of "Tasks"
Description, Due Date are the values
You're attaching a listener to /Tasks/$titleOfTask in your JSON, say /Tasks/Alpha. That listener is asking to be called for the first child node of /Tasks/Alpha, so the snapshot in your code will point to /Tasks/Alpha/Description. When you then print taskDict["Description"], you are printing the value of /Tasks/Alpha/Description/Description, which does not exist.
The simplest fix is to listen for the .value event:
taskRef?.observeSingleEvent(of: .value, with: { (snapshot) in
if let taskDict = snapshot.value as? [String:Any] {
print("Printing ---------> ",taskDict["Description"] as Any)
}
})
Now the snapshot has all data from /Tasks/Alpha, and thus the taskDict["Description"] ends up being the value from /Tasks/Alpha/Description.

How to unpack multiple levels of nested JSON in Firebase Database

In my app, I would regularly have a JSON topic, for example message, then nested in that is a random ID, then the message text as a string inside the random ID. But, I need to decipher multiple levels of random IDs. Is that possible in Firebase for Swift? This is what I mean:
This is my code:
Database.database().reference().child("app").observe(.childAdded) { (snapshot) in
//app is first in the JSON tree
let dict = snapshot.value as! [String: Any]
let msg = dict["message"] as! String
Obviously this is crashing the app, as it's looking for "Message" in the first RandomID. Is there a solution to this? I haven't found resources for specifically what I'm looking for. Thank you.
You'll want to loop over the children of snapshot as shown here:
Database.database().reference().child("app").observe(.childAdded) { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot //downcast
let dict = snap.value as! [String: Any]
let msg = dict["message"] as! String
}
})
Also see:
Get data out of array of Firebase snapshots
Swift Firebase -How to get all the k/v when using queryOrdered(byChild: ).queryEqual(toValue: )
other questions about looping over child nodes

I need help getting values out of a snapshot from firebase

My Data in Firebase looks like this:
I am retrieving the data with
var ref: DatabaseReference
ref = Database.database().reference()
ref.child("peopleReminders").child("-LBO0TMbOM0cwd5TMMiP").observe(.value) { snapshot in
for value in snapshot.children {
print(value)
}
}
This prints the following:
Snap (0) r04
Snap (1) r02
Snap (2) r01
This should be an array. What I need to do is get the values R04, R02, and R01 out of it.
You don't need a loop or enumeration to parse it into an array as Firebase supports both Array and Dictionary. You can directly cast the result into an array. Below piece of code will work:
ref.child("peopleReminders").child("-LBO0TMbOM0cwd5TMMiP").observeSingleEvent(of: DataEventType.value) { (snapshot) in
if snapshot.exists() {
let result: [String] = snapshot.value as? [String] ?? []
print(result)
}
}
Note: Always check snapshot existence it will be false if data doesn't exist for the requested reference. Use observeSingleEvent when you need to fetch the data for once if you use observe the call back will be call many times whenever there is a change in requested node so that delete, insert, update etc.
I replaced for value in snapshot.children with the following code.
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
print(rest.value!)
}
The new output is now:
R04
R02
R01

Firebase queryEqualToValue

I have the current Firebase Database structure.
I'd like to query all the true/false values.
Current code I have is;
let resultsRef = Database.database().reference().child("user_results").child(userID)
let query = resultsRef.queryOrderedByKey().queryEqual(toValue: "false")
query.observeSingleEvent(of: .value, with: { (snapshot) in
userID is "MyRQOZ..."
Printing out snapshot gives me nothing. However, if I do
.queryLimited(toFirst: 1)
I get the snapshot I want.
["yhgeZLXJhuXKmbnK1eRwkC4xmO84": false]
I believe on my ref I need to go one path further down. But I don't know what id would be.
You're only querying the first event
observeSingleEvent
Try
query.observe(.childAdded, with: { (snapshot) in
and add an if statement to catch the values
(Edit) Add this If Statement under the original bit of code that you have already, like this:
let resultsRef = Database.database().reference().child("user_results").child(userID)
let query = resultsRef.queryOrderedByKey().queryEqual(toValue: "false")
query.observeSingleEvent(of: .value, with: { (snapshot) in
if let trueOrFalse = snapshot.value as? [String: AnyObject] {
for (ke, value) in trueOrFalse {
if value as! String == "false" {
// 'ke' is now all of the keys where the value so you could do something like...
print(ke) //and it will give you the keys that have false as the value.

Firebase Swift: Converting Snapshots to Dictionary

I have the following snapshots and I'm trying to create an array of dictionary. I have been fiddling ways to cast as [String: Bool] or getting snapshot.value or whatsoever but can't seem to work correctly. Any advice how can I go about doing it?
ref.child("activities").child(userUID!).observe(.childAdded, with: { (snapshot) in
print(snapshot)
}) { (error) in
print(error.localizedDescription)
}
The snapshots looks like this:
Snap (Person1) 0
Snap (Person2) 0
Snap (Person3) 0
I am trying to write an array like this:
Optional(["Person3": false, "Person2": false, "Person1": false])
Some advice is much appreciated, thanks!
You need to cast the snapshots value as [String:Bool]. You can do it with the code below.
snapshot.value as? [String:Bool]
Edit:
You say it doesn't work...are you sure that you have any data to retrieve?
If you do like this you'll find out if you have any data.
if let value = snapshot.value{
//there is data available
let data = value as [string:Any]
print("\(data)")
}else{
//there is no data available. snapshot.value is nil
print("No data available from snapshot.value!!!!")
}