Retrieve a Childs Child in Firebase - Unwrap unique-post-ids - swift

I am trying to unwrap data in childs from childs basically. My current database structure looks like this:
- user-posts
- <user-id>
- user-data
- <unique-post-id> (As a result from childByAutoId)
- the data I want to display
- <unique-post-id> (As a result from childByAutoId)
- the data I want to display
...
-<user-id>
-...
-<user-id>
...
So as it can be seen, the actual data I want to retrieve is always a child of <unique-post-id>, which is automatically generated when the data is written to the database. Retrieving from the database I so far only get:
- <unique-post-id>
- <unique-post-id>
- ...
Is there a way of unwrapping those and display their childs? What is working for me now is displaying all the unique post id's, but I can't figure out how to get then the child below them, and that for all of them.
The code I'm using to retrieve the data:
func getQuery() -> FIRDatabaseQuery {
let myTopPostsQuery = (ref.child("user-posts")).child(getUid()).child("user-data")
return myTopPostsQuery
}
dataSource = FirebaseTableViewDataSource.init(query: getQuery(),cellReuseIdentifier: "Cellident", view: self.tableView)
dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
cell.textLabel?.text = snap.key as String
}

dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
cell.textLabel?.text = snap.key as! String
let childString = snap.value as! String
// If the child is another dictionary use `as! [String : AnyObject]`
}
But a different approach might go like this : -
ref.child("user-posts")).child(getUid()).child("user-data").observeEventType(.Value, withBlock: { (snap) in
if snap.exists(){
for each in snap as! [String : AnyObject] {
let childString = snap.Value as! String
}
}
})

Related

How to read all child data from firebase

How can i read all child data from Firebase.
let ShopRef = Database.database().reference(withPath: “ShoppingMallLst”).child(“ShoppingMall1”)
ShopRef.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.childrenCount > 0 {
for data in snapshot.children.allObjects as! [DataSnapshot] {
if let data = data.value as? [String: Any] {
let Description = data["Description"] as? String
let Floor = data[“Floor”] as? Int
….
}
}
}
})
But how can i read the data from child "ShopPath?"
child "ShopPath" has type [String: [String: String]]
you can try:
let ShopPath = data["ShopPath"] as? [String: [String: String]]
The key to firebase is to keep data in snapshots as long as you can. So in this case instead of casting items to dictionaries, which loose ordering or arrays that get more complex as the structure gets deeper, leverage DataSnapshots.
Here's the main function to read all shops in ShoppingMall1 - similar to the code in your question.
func readMallShops() {
let ref = self.ref.child("ShoppingMallList").child("ShoppingMall1")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allShopsSnap = snapshot.children.allObjects as! [DataSnapshot]
for shopSnap in allShopsSnap {
let shop = ShopClass(withSnap: shopSnap)
}
})
}
Then a class that holds data about each shop. Note that I pass each snapshot in to initialize the class
class ShopClass {
var name = ""
var height = ""
convenience init(withSnap: DataSnapshot) {
self.init()
let name = withSnap.childSnapshot(forPath: "ShopName").value as? String ?? "No Shop Name"
print("Shop: \(name)")
self.name = name
let shopPathSnap = withSnap.childSnapshot(forPath: "ShopPath")
let shopChildSnap = shopPathSnap.children.allObjects as! [DataSnapshot]
for childDataSnap in shopChildSnap { //iterate over the array in ShopPath
let height = childDataSnap.childSnapshot(forPath: "Height").value as! String
print(" height: \(height)")
self.height = height
}
}
}
And the output looks like this
Shop name: Test
height: 1,180
Shop name: Test 2
height: 2,000
I left off the other child nodes as if you can read height, you can read the rest. So this just assigns and prints out the shop name and height (as a string).
A suggestion as well. Arrays are not well suited for NoSql databases and their use is very situational (avoid if possible). If you're using an array, there's probably a better structure available.

Cannot fetch / read data from firebase real-time database to UITableViewController

I am able to successfully write data from my application to my firebase real-time database. I cannot retrieve the data and display it in a UIViewController.
I have search stack, YouTube and firebase docs and no luck. I printed out the count and it returns 0. I believe the For loop isn't iterating or its not appending to my array correctly. I have trie force wrapping and unwrapping refRepairs, and placing databaseHandle in from of it.
override func viewDidLoad() {
super.viewDidLoad()
refRepairs = Database.database().reference().child("repairs");
//observing the data changes
refRepairs!.child("repairs").observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.repairList.removeAll()
//iterating through all the values
for repairs in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let repairObject = repairs.value as? [String: AnyObject]
let brand = repairObject?["brand"]
let id = repairObject?["id"]
let modelNumber = repairObject?["modelNumber"]
//creating artist object with model and fetched values
let repair = RepairModel(id: id as! String?, brand: brand as! String?, modelNumber: modelNumber as! String?)
//appending it to list
print(snapshot.childrenCount)
self.repairList.append(repair)
}
//reloading the tableview
self.doListTableView.reloadData()
}
})
}
I made the changes and it was working!!! Now, I am trying to add records to the database by uid, and I have successfully done it. Now I have the same problem where I can't display the records. I printed the count and it returns 1 record which is correct. Here is the new code.
override func viewDidLoad() {
super.viewDidLoad()
refRepairs = Database.database().reference().child("repairs");
//observing the data changes
//refRepairs!.child("uid").observe(DataEventType.value, with: { (snapshot) in
//observing the data changes
refRepairs!.observe(DataEventType.value, with: { (snapshot) in
//if the reference have some values
if snapshot.childrenCount > 0 {
//clearing the list
self.repairList.removeAll()
//iterating through all the values
for repairs in snapshot.children.allObjects as! [DataSnapshot] {
//getting values
let repairObject = repairs.value as? [String: AnyObject]
let brand = repairObject?["brand"]
let uid = repairObject?["uid"]
let id = repairObject?["id"]
let modelNumber = repairObject?["modelNumber"]
//creating artist object with model and fetched values
let repair = RepairModel(uid: uid as! String?, id: id as! String?, brand: brand as! String?, modelNumber: modelNumber as! String?)
//appending it to list
print(snapshot.childrenCount)
self.repairList.append(repair)
}
//reloading the tableview
self.doListTableView.reloadData()
}
})
}
You are looking another second child called repairs when you are "observing the data changes". Try this:
override func viewDidLoad() {
super.viewDidLoad()
refRepairs = Database.database().reference().child("repairs");
//observing the data changes
refRepairs!.observe(DataEventType.value, with: { (snapshot) in
...
If that don't work. Use the observeSingleEvent method from Firebase

Issues when trying to remove the firebase reference

I am having some issues while trying to delete one of the tableView row - in my case I was trying to delete the data from Firebase and then reload the table view.
See the function below:
func deleteMeds() {
Database.database().reference().child("Meds_Database").child("UsersID").child((Auth.auth().currentUser?.uid)!).child("User_Medications").observe(DataEventType.childRemoved, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let medication = Meds()
medication.medName = (dictionary["Medication_Name"]) as! String
medication.medDosage = (dictionary["Medication_Dosage"]) as! String
medication.medEdit = (dictionary["Medication_Frequency"]) as! String
medication.medAlarm = (dictionary["Medication_Reminder"]) as! String
self.meds.remove(at: 0)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
print(snapshot)
}, withCancel: nil)
}
I think I am getting confused with the Firebase Syntax... Can somebody help me? The database is like this:
I am sure someone can help
You only need to delete the relavant object not always index 0 here
self.meds.remove(at: 0)
So replace it with
self.meds = self.meds.filter{ $0 != medication }
and adopt the Equatable protocol

Swift Firebase read children of a child

So I am trying to read the children of the autoID children beneath "Recipes" below is a picture of my Firebase database and beneath that is the method that is supposed to retrieve the value of "Description" and "Name" and insert them into variables.
The error that I am currently getting when running the app is this:
Could not cast value of type '__NSCFString' (0x10ad2afb8) to 'NSDictionary' (0x10ad2bfa8).
ref = Database.database().reference()
databaseHandle = ref?.child("Recipes").observe(.childAdded) { (snapshot) in
for snap in snapshot.children
{
let recipeSnap = snap as! DataSnapshot
let recipeID = recipeSnap.key
let dict = recipeSnap.value as! [String:AnyObject]
let recipeName = dict["Name"] as! String
let recipeDescription = dict["Description"] as! String
print("key = \(recipeID) and name = \(recipeName) and description = \(recipeDescription)")
}
}
The print statement is just there for testing.
Try the following and let me know if it works now:
// SEARCHES FOR SHARING CODE IN DATABASE (ONLINE)
let parentRef = Database.database().reference().child("Recipes")
parentRef.observeSingleEvent(of: .value, with: { snapshot in
// SHOWING WHATEVER WAS RECEIVED FROM THE SERVER JUST AS A CONFIRMATION. FEEL FREE TO DELETE THIS LINE.
print(snapshot)
// PROCESSES VALUES RECEIVED FROM SERVER
if ( snapshot.value is NSNull ) {
// DATA WAS NOT FOUND
print("– – – Data was not found – – –")
} else {
// DATA WAS FOUND
for user_child in (snapshot.children) {
let user_snap = user_child as! DataSnapshot
let dict = user_snap.value as! [String: String?]
// DEFINE VARIABLES FOR LABELS
let recipeName = dict["Name"] as? String
let recipeDescription = dict["Description"] as? String
print("– – – Data for the recipe \(recipeName) with the description \(recipeDescription) was found successfully! – – –")
}
}
}
If you only want to retrieve the name and description for one specific recipe, you should change the third line to
parentRef.queryEqual(toValue:DefineWhatToSearchForHere).observeSingleEvent(of: .value, with: { snapshot in
If you constantly want to update to reflect changes, you can either call this function every x seconds using a timer and adding it to override func viewDidLoad() such as
time = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(ViewController.updateFBData), userInfo: nil, repeats: true)
after creating a function called func updateFBData() in which you do whatever you want to do to get new data (see above) and calling it in a defined timeInterval
or you can do what Attila Hegedüs in this excellent tutorial.

Retrieve only the Value without the Key in Firebase

So I'm trying to retrieve only the "second" value of a child from my firebase database.
The structure looks like this:
And what I'm getting as an output is this:
However what I actually want is just:
someURL.com
Ideally even without the https or http (where I probably need an if to check, since it is not known for all of them in advance). I guess there are 2 options, either unwrapping the string in Swift, or (what I was hoping for) just retrieving the actual value without the brackets and "url" in the beginning. I couldn't find a similar problem on here yet.
My code for retrieving:
dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
let childString = snap.value as! [String : AnyObject]
cell.textLabel?.text = String(childString)
}
Try this
dataSource?.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FIRDataSnapshot
let childString = snap.value as! [String : AnyObject]
if let url = childString["url"] as? String {
cell.textLabel?.text = url
} else {
print("No value for url")
}
}
childString variable you are using is a dictionary which has values for keys. You need to fetch the value for the key "url".