Convert Firebase Dictionary Data to Array (Swift) - ios

This may be a simple answer, so apologies in advance, but I'm stuck because I'm still getting head wrapped around how Firebase works. I want to query a Firebase Database based on unix date data that is saved there and then take the related "Unique ID" data and put it into an array.
The data in Firebase looks like this:
posts
node_0
Unix Date: Int
Unique ID Event Number: Int
node_1
Unix Date: Int
Unique ID Event Number: Int
node_2
Unix Date: Int
Unique ID Event Number: Int
What I have so far is as follows. The query part seems to be working as expected. Where I'm struggling is how to put the "Unique ID Event Number" data into an array. This is the approach that seemed closest to success, which is based on this post, but I get an error that child has no member of "value".
// Log user in
if let user = FIRAuth.auth()?.currentUser {
// values for vars sevenDaysAgo and oneDayAgo set here
...
let uid = user.uid
//Query Database to get the places searched by the user between one and seven days ago.
let historyRef = self.ref.child("historyForFeedbackLoop/\(uid)")
historyRef.queryOrdered(byChild: "Unix Date").queryStarting(atValue: sevenDaysAgo).queryEnding(atValue: oneDayAgo).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("error")
} else {
for child in snapshot.children {
if let uniqueID = child.value["Unique ID Event Number"] as? Int {
arrayOfUserSearchHistoryIDs.append(uniqueID)
}
}
}
})
} else {
print("auth error")
}
Any ideas are greatly appreciated!

Try using this:-
historyRef.queryOrdered(byChild: "Unix Date").queryStarting(atValue: sevenDaysAgo).queryEnding(atValue: oneDayAgo).observeSingleEvent(of: .value, with: { snapshot in
if let snapDict = snapshot.value as? [String:AnyObject]{
for each in snapDict{
let unID = each.value["Unique ID Event Number"] as! Int
arrayOfUserSearchHistoryIDs.append(unID)
}
}else{
print("SnapDict is null")
}
})

I ended up re-working how I read the Firebase data based on the approach outlined in this post. The actual working code I used follows in case it's helpful for someone else.
// Log user in
if let user = FIRAuth.auth()?.currentUser {
let uid = user.uid
// values for vars sevenDaysAgo and oneDayAgo set here
...
let historyRef = self.ref.child("historyForFeedbackLoop/\(uid)")
historyRef.queryOrdered(byChild: "Unix Date").queryStarting(atValue: sevenDaysAgo).queryEnding(atValue: oneDayAgo).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("user data not found")
}
else {
for child in snapshot.children {
let data = child as! FIRDataSnapshot
let value = data.value! as! [String:Any]
self.arrayOfUserSearchHistoryIDs.append(value["Unique ID Event Number"] as! Int)
}
}
})
}

Related

I cannot retrieve data from Firebase database

I setup Firebase database like this:
dataS
- LjYal4ijEdjfafe
- email: "abc#xxx.org"
- firstname: "aa"
- lastname: "bb"
And I cannot retrieve data "lastname", it always return nil.
let ref = Database.database().reference()
ref.queryOrdered(byChild: "email").queryEqual(toValue: email1).observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
print("cannot find in firebase")
return
}
let value1 = snapshot.value as? NSDictionary
let lastnameP = value1?["lastname"] as? String ?? ""
print(lastnameP)
There are a few issues with the code.
The first is when observing by .value, all of the matches will be returned whether it be 1 or 1000 so that returned DataSnapshot will need to be iterated over to access the child data, even if there's 1. If using .childAdded, it will return one at a time in the snapshot if using .observe, and only the first using .childAdded.
Second thing is the reference is pointing at the root reference. It appears dataS may be a child of the root
root_firebase
dataS
uid
email
firstname
lastname
if not, then keep in mind this code matches that structure.
Last thing is to make it more Swifty and use modern function calls and add a little error checking in case the lastname node is not found with the nodes being read.
let email1 = "email to query for"
let ref = Database.database().reference()
let nodeToQueryRef = ref.child("dataS")
nodeToQueryRef.queryOrdered(byChild: "email")
.queryEqual(toValue: email1)
.observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() == false {
print("cannot find in firebase")
return
}
let returnedSnapshotArray = snapshot.children.allObjects as! [DataSnapshot]
for snap in returnedSnapshotArray {
let key = snap.key
let lastName = snap.childSnapshot(forPath: "lastname").value as? String ?? "No Last Name"
print(key, lastName)
}
})

Swift 3 Firebase retrieving key and passing to view controller

I've spend hours looking at identical questions but none of the answers I've found are helping this issue. Simple app retrieves data from Firebase Database and passes to another view controller from the tableview. The main data will pass through but I can't edit the information without an identifying "key" which I tried to set as childByAutoID() but then changed to a timestamp. Regardless of the method, all I get is the entries info not the actual key itself.
func loadData() {
self.itemList.removeAll()
let ref = FIRDatabase.database().reference()
ref.child(userID!).child("MyStuff").observeSingleEvent(of: .value, with: { (snapshot) in
if let todoDict = snapshot.value as? [String:AnyObject] {
for (_,todoElement) in todoDict {
let todo = TheItems()
todo.itemName = todoElement["itemName"] as? String
todo.itemExpires = todoElement["itemExpires"] as? String
todo.itemType = todoElement["itemType"] as? String
self.itemList.append(todo)
print (snapshot.key);
}
}
self.tableView.reloadData()
}) { (error) in
print(error.localizedDescription)
}
}
If your data looks like this:
Uid: {
MyStuff: {
AutoID: {
itemName: “Apocalypse”,
itemExpires: “December 21, 2012”,
itemType: “Catastrophic”
}
}
}
Then I would query like this:
ref.child(userID!).child("MyStuff").observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let child = child as? DataSnapshot
let key = child?.key as? String
if let todoElement = child?.value as? [String: Any] {
let todo = TheItems()
todo.itemName = todoElement["itemName"] as? String
todo.itemExpires = todoElement["itemExpires"] as? String
todo.itemType = todoElement["itemType"] as? String
self.itemList.append(todo)
self.tableView.reloadData()
}
}
})
Additionally, like I said in my comment you can just upload the key with the data if you’re using .updateChildValues(). Example:
let key = ref.child("userID!").childByAutoId().key
let feed = ["key": key,
“itemName”: itemName] as [String: Any]
let post = ["\(key)" : feed]
ref.child("userID").child("MyStuff").updateChildValues(post) // might want a completionBlock
Then you can get the key the same way you are getting the rest of the values. So your new data would look like this:
Uid: {
MyStuff: {
AutoID: {
itemName: “Apocalypse”,
itemExpires: “December 21, 2012”,
itemType: “Catastrophic”,
key: “autoID”
}
}
}
The key you are trying to look for is located in the iterator of your for loop
Inside your if-let, try to do this:
for (key,todoElement) in todoDict {
print(key) // this is your childByAutoId key
}
This should solve the problem. Otherwise show us a screen of your database structure

Can't load in values for tableview cell firebase

I'm trying to load in different values for each cell in a tableview. Currently, I load in a teamID, display it on the current cell, then use that ID to load in the other attributes of the team.
self.ref?.child("Teams").child(currentTeamID).child("Number").observeSingleEvent(of: .value, with: { (snapshot) in
let number1 = snapshot.value as? Int
if let teamNum = number1 {
Cell.teamNumber.text = "team " + String(teamNum)
//breakpoint
}
})
self.ref?.child("Teams").child(currentTeamID).child("memberCount").observeSingleEvent(of: .value, with: { (snapshot) in
let memcon = snapshot.value as? Int
if let membercount = memcon {
Cell.userCount.text = "Members: " + String(membercount)
//breakpoint
}
})
return Cell
My issues comes when trying to load in these other attributes. Should I be doing this is a different way? Right now it loads only the second .observeSingleEvent I have tried placing breakpoint where I indicated above, but only the second one ever gets hit. Do I need a separate reference or is there a way to load all the values from a parent object?
Thanks a whole bunch.
Added Firebase Structure:
ftc-scouting-app
Teams
Brophy Robotics
Name: "Brophy Robotics"
Number: "201"
Password: "bronco"
memberCount: 2
memberList
member1: "5ilQc8KlrERLAmtFXjWaOZLIcoC3"
member2: "syV9SS6S9hY8PyKBOC0VQ3NNv0v2"
Users
5ilQc8KlrERLAmtFXjWaOZLIcoC3
(User Info Values)
syV9SS6S9hY8PyKBOC0VQ3NNv0v2
(User Info Values
The values I'm trying to load are the team number and the member count. I want to put them on the cell as it loads in each team that each user has. So, I just need it to load each value and put it on my custom table view cell that has all the fields for it. To clarify - I already know that it retrieves the team ID properly because it is able to put it on the cell.
The value currentTeamID is a value that I have already loaded in, and is the id (which is the same as the name) of the current cell's prospective team.
First, change the structure
ftc-scouting-app
Teams
Jyis9009kos0kslk //should be generated with childByAutoId()
Name: "Brophy Robotics"
Number: "201"
Password: "bronco"
memberCount: "2"
memberList:
5ilQc8KlrERLAmtFXjWaOZLIcoC3: true //uid as the key
syV9SS6S9hY8PyKBOC0VQ3NNv0v2: true
Users
5ilQc8KlrERLAmtFXjWaOZLIcoC3
(User Info Values)
syV9SS6S9hY8PyKBOC0VQ3NNv0v2
(User Info Values)
Then, let's retrieve just the one team node and get some data
let teamsRef = self.ref.child("ftc-scouting-app").child("Teams")
let thisTeamRef = teamsRef.child("Jyis9009kos0kslk")
thisTeamRef.observeSingleEvent(of: .value, with: { snapshot in
let teamDict = snapshot.value as! [String: AnyObject]
let teamName = teamDict["Name"] as! String
print(teamName)
let memCount = teamDict["memberCount"] as! String
print(memCount)
let memberList = teamDict["memberList"] as! [String: AnyObject]
for user in memberList {
print(user.key)
}
})
and the output is
Brophy Robotics
2
5ilQc8KlrERLAmtFXjWaOZLIcoC3
syV9SS6S9hY8PyKBOC0VQ3NNv0v2
each event events asynchronously. you should use completion block in your each event.
func getNumber (completion: #escaping (String)->()){self.ref?.child("Teams").child(currentTeamID).child("Number").observeSingleEvent(of: .value, with: { (snapshot) in
let number1 = snapshot.value as? Int
if let teamNum = number1 {
completion(String(teamNum))
}
})}
getNumber(completion: {(teamNum) in
self.ref?.child("Teams").child(currentTeamID).child("memberCount").observeSingleEvent(of: .value, with: { (snapshot) in
let memcon = snapshot.value as? Int
if let membercount = memcon {
Cell.teamNumber.text = "team " + teamNum
Cell.userCount.text = "Members: " + String(membercount)
//breakpoint
}
})
})

TableView Duplicates and firebase search query

I have two issues with the snippet below.
I have get duplication in my TableView.
When I search for something that returns a result, and I tried searching for another thing that returns a result, the existing result will be the one showing not the new result, for example:
a. I search for "ola" and my TableView returns a list of -> olabode, olatunde, olaide.
b. Then I searched for "bisi", if found matching query for "bisi" I still get the query result for "ola".
func searchView(_ searchView: AZSearchViewController, didTextChangeTo text: String, textLength: Int) {
self.resultArray.removeAll()
searchView.reloadData()
guard text != "" else {
return
}
AppFirRef.userRef.queryOrdered(byChild: "username")
.queryStarting(atValue: text)
.queryEnding(atValue: text + "\\uf8ff")
.observe(.value, with: { (snapshot) in
if (snapshot.value is NSNull) {
print("not found")
} else {
print("found")
self.resultArray.removeAll()
searchView.reloadData()
print("\(snapshot.value)")
for case let snap as FIRDataSnapshot in snapshot.children {
guard let value = snap.value as? [String : Any] else { continue }
//print("\(snap.key)")
print(value)
let user = LContact(value: value, searchUserId: snap.key)
self.set.add(user)
if let username = user.username{
self.resultArray.append(username.lowercased())
searchView.reloadData()
}
}
}
})
}
It might be too late, but change
.observe(.value, with: { (snapshot) in
...
)}
to
.observeSingleEvent(of: .value, with: { (snapshot) in
...
)}
see my answer to this question for the explanation; it applies to you as well because you are also appending to the array every time the data at your reference path changes (such as when someone on another device changes data in the userRef reference path.

How to extract child of node in data snapshot

My firebase set up is as such:
Parent_node:{
Type:{
1476663471800:{ //This is a timestamp = Int64(date.timeIntervalSince1970 * 1000.0)
uid: USERS_UID;
}
}
}
how would I access the users uid? I have tried the following code, but its not extracting the UID
self.databaseRef.child("Parent_node/\(Type)").queryLimitedToLast(5).observeEventType(.Value, withBlock: { (snapshot) in
print(snapshot)
if let userDict = snapshot.value as? [String:AnyObject]{
for each in userDict{
let uidExtraced = each
print(uidExtraced)
//("1476663471700", [uid: USERS_UID])
First of all use snapshot.value?.allValues to get values and than parse it...
if snapshot.exists() {
for value in (snapshot.value?.allValues)!{
print(value) // you get [uid: USERS_UID] here
// ... parse it to get USERS_UID
print("user_id -- \(value["uid"])")
}
}
With this method, order of child might be different. For ordered nodes, you can use snapshot.child

Resources