Firebase retrieve autoId value in swift - ios

I would like to retrieve images values. Node look like this so, I would like to retrieve url1, url2, url3.
"Post": {
"uid": {
"Text": "some text",
"images": {
autoID1: url1,
autoID2: url2,
autoID3: url3
}
}
}
The problem is that key is auto generated. So, I usually cast like this.
if let dictionary = snapshot.value as? [String:Anyobject]
let text = dictionary["text"] as? String
but in this case I don't know how to cast autoID key and get value.
I tried code below but error said
Could not cast value of type '__NSDictionaryM' (0x10af491c8) to
'NSString' (0x10a0bad68).
func fetchImages() {
ref.child("Post").child(uid!).child("images").observe(.value, with: { (snapshot) in
let downloadUrl = snapshot.value as! String
let stoRef = Storage.storage().reference(forURL: downloadUrl)
stoRef.getData(maxSize: 1*1024*1024, completion: { (data, error) in
let pic = UIImage(data: data!)
self.imagesArray.append(pic!)
})
}, withCancel: nil)
}
also if there are three url, should I use like for snap in snapshot.children to loop through? How should I loop through those url and put into imagesArray?
Thank you in advance!

You are very close. The thing to remember is that when you get the
.child("images")
it's actually a node that contains children
"images": {
autoID1: url1,
autoID2: url2,
autoID3: url3
and isn't a string but another key: value pair where the key is "images" and the value is the child nodes.
To get the children, iterate over the child nodes in the snapshot, casting each one as a snapshot (another key: value pair) with the key being autoID1 etc and the value is the url (a String)
let imagesRef = self.ref.child("Post").child("uid_0").child("images")
imagesRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
//let key = snap.key //autoID1, autoID2 etc
let downloadUrl = snap.value as! String
let stoRef = Storage.storage().reference(forURL: downloadUrl)
//get your pic
}
})
if ref is a class var, as it appears in your question, it should be referenced as
self.ref
Also, if you want to leave an observer on the node so you can be notified of changes, use .observe. In my case I just wanted to read it one time so I used observeSingleEvent as I only wanted to read it once.

Related

how to get data from child node in firebase in iOS

my database structure is
appname:
Tasks:
childbyautoid1:
"name": "myname"
"age": "18"
childbyautoid2:
"name": "yourname"
"age": "20"
I want to know how to get all data that is name and age of all the child node as I don't know the childbyautoid
I am writing
Database.database().reference().child("Tasks").observe(.childAdded){ (dss) in
if let value = dss.value as? [String: AnyObject]{
let name = value["name"] as? String
let age = value["age"] as? String
print(name)
print(age)
}
You can go through every child like this:
// Create a reference to the database path
let ref = Database.database().reference(withPath: "Tasks")
// You can keep your database synced
ref.keepSynced(true)
ref.observe(.value, with: { (snapshot) in
// Checking if the reference has some values
if snapshot.childrenCount > 0 {
// Go through every child
for data in snapshot.children.allObjects as! [DataSnapshot] {
if let data = data.value as? [String: Any] {
// Retrieve the data per child
// Example
let name = data["name"] as? String
let age = data["age"] as? String
// Print the values for each child or do whatever you want
print("Name: \(name)\nAge: \(age)")
}
}
}
})
Try [[String: Any]] instead of [String: Any] then loop inside of it for each Dictionary and map out result, should be something like this.
if let value = dss.value as? [[String: Any]]{
for val in value {
let name = val["name"] as? String
let age = val["age"] as? String
print(name)
print(age)
}

How to get values inside nested keys in Firebase on Swift

I'm trying to get values inside two nested keys in Firebase.
:
I need to put all the value of name inside an array. Here is my code where I'm accessing just the node "user". I was thinking that I could use "queryOrderedByKey" one after another, but in that case xCode crashes and says something like multiple quires aren't allowed.
Database.database().reference().child("user").queryOrderedByKey().observe(.childAdded) { (snapshot) in
if snapshot.value != nil {
let result = snapshot.value as! [String : AnyObject]
if let name = result["name"] as? String {
self.myArray.append(name)
}
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}
And this is what I'm getting when printing the result.
Here is the answer
Database.database().reference().child("user").observe(.childAdded) { (snapshot) in
if let dictinoary = snapshot.value as? [String: Any] {
if let myFinalStep = dictinoary["GeneralInformation"] as? [String: Any] {
print(myFinalStep["name"])
}
}
}
Tigran's answer is very good but here's an alternative. This code iterates over each child node within 'user' node and looks into a deep path to get the name. Note this leaves a childAdded observer to the user node so if any additional nodes are added, this will fire again.
let usersRef = self.ref.child("user")
usersRef.observe(.childAdded, with: { snapshot in
if let name = snapshot.childSnapshot(forPath: "GeneralInformation")
.childSnapshot(forPath: "name").value as? String {
print(name)
}
})
If you want to read the names in once and not leave an observer, here's an alternative
let usersRef = self.ref.child("user")
usersRef.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
if let name = snap.childSnapshot(forPath: "GeneralInformation")
.childSnapshot(forPath: "name").value as? String {
print(name)
}
}
})
I was feeling Swifty so here's a third variant if you don't want to leave an observer. Note that if the node containing the name does not exist, the resulting array will contain "No Name" at that index.
let usersRef = self.ref.child("uses")
usersRef.observeSingleEvent(of: .value, with: { snapshot in
let myUsers = snapshot.children.allObjects.map { $0 as! DataSnapshot }
let names = myUsers.map { $0.childSnapshot(forPath: "GeneralInformation")
.childSnapshot(forPath: "name")
.value as? String ?? "No Name" }
print(names)
})

How to cast 'FIRDataSnapshot' to NSString & NSDict

I'm getting the error of could not cast value of type 'FIRDataSnapshot' to 'NSString'. Neither the retrieve names or retrieve quantities/manfacturers is working. Both give the same casting error essentially.
ref = Database.database().reference()
// Retrieve Names
ref.child("rawMaterials").observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
self.rawMaterialNames.append(child as! String)
}
})
//Retrieve Quantities and Manfacturers
for name in rawMaterialNames {
ref.child("rawMaterials/\(name)").observe(.value, with: { (snapshot) in
if let data = snapshot.value as? [String: Any] {
for i in data {
let quantity = data["quantity"] as! String
let manafacturer = data["manafacturer"] as! String
self.rawMaterialManafacturers.append(manafacturer)
self.rawMaterialQuantities.append(quantity)
//self.rawMaterialQuantities.append(data!["quantity"] as! String)
//self.rawMaterialManafacturers.append(data!["manafacturer"] as! String)
}
}
})
Edit: Since, no one has been able to help, maybe I'm not providing enough. My firebase realtime database tree looks like this
App Name
-contracts
---ContractTest
-rawMaterials
---Optional("Paint")
--------manafacturer: "Optional(\"Paint Company A\")"
--------quantity: "Optional(\"120\")"
---Optional("Lead")
You are missing a step to be able to cast to String:
ref.child("rawMaterials").observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let nameSnapshotValue = child.value as! FIRDataSnapshot
let name = nameSnapshotValue["name"] as! String //or whatever the dictionary key is...
self.rawMaterialNames.append(name)
}
})

Iterate through all keys of one child in Firebase

This is my structure in the Firebase Realtime database:
I want to get for all products the name.
Here's what I tried:
database.child("customerID").child("productTopSeller").observe(FIRDataEventType.value, with: { (snapshot) in
for childSnap in snapshot.children.allObjects {
let product = childSnap as! FIRDataSnapshot
print(product.value?["name"] as? String ?? "")
}
}) { (error) in
print(error.localizedDescription)
}
But this gives my following error:
Type 'Any' has no subscript members.
I know I would need to cast the snapshot somehow but couldn't figure out how to do this. using Swift 3.
You need to cast product.value to [String:Any]. Look ad the following code
ref.child("customerID").child("productTopSeller").observeSingleEvent(of: .value, with: { snapshot in
let names = snapshot
.children
.flatMap { $0 as? FIRDataSnapshot }
.flatMap { $0.value as? [String:Any] }
.flatMap { $0["name"] as? String }
print(names)
})
Please note I am using observeSingleEvent in order to get only one callback from Firebase.
Your code does use observe instead which produce a callback every time the observed data does change.

Read array inside snapshot in Firebase with Swift

Need help trying to read an array of this form:
As far as I tried, I got this
let defaults = UserDefaults.standard
let userUuid = defaults.string(forKey: defaultsKeys.keyOne)
let ref = FIRDatabase.database().reference().child("images").child("\(userUuid!)")
let filterQuery = ref.queryOrdered(byChild: "uuid").queryEqual(toValue: "\(uuid)") // where uuid is a value from another view
filterQuery.observe(.value, with: { (snapshot) in
for images in snapshot.children {
print(images)
}
})
But I receive nothing. I want to read the images' links to show them in the view controller.
Make sure that the uuid var in the line below is not an optional value (or if it is, unwrap it) because otherwise you'll be querying to compare to "Optional(myUuidValue)" instead of "myUuidValue"
let filterQuery = ref.queryOrdered(byChild: "uuid").queryEqual(toValue: "\(uuid)")
The snapshot in the line below contains more than just the images, it has all the other children under that uuid
filterQuery.observe(.value, with: { (snapshot) in })
So extract the images like this:
filterQuery.observe(.value, with: { (snapshot) in
let retrievedDict = snapshot.value as! NSDictionary
let innerDict = retrievedDict["KeyHere"] as! NSDictionary // the key is the second inner child from images (3172FDE4-...)
let imagesOuterArray = userDict["images"] as! NSArray
for i in 0 ..< imagesOuterArray.count {
let innerArray = imagesOuterArray[i] as! NSArray
for image in innerArray {
print(image as! String)
}
}
})
Clarification: cast all the children of the uuid as an NSDictionary, then extract the nested arrays using those two for-loops
Update
Thanks to Jay for pointing out the error! Also, as Jay suggested, consider restructuring your database and replacing those arrays with dictionaries that perhaps contain the URL, path (for deleting purposes if you need that), and timestamp of each image.
After strugling for the answer, got this code works
let ref = FIRDatabase.database().reference().child("images").child("\(userUuid!)")
let filterQuery = ref.queryOrdered(byChild: "identifier").queryEqual(toValue: "\(identifier)")
filterQuery.observe(.value, with: { (snapshot) in
for child in snapshot.children {
if (child as AnyObject).hasChild("images") {
let images = (images as AnyObject).childSnapshot(forPath: "images").value! as! NSArray
for i in images {
for j in i as! [AnyObject] {
let url = NSURL(string: j as! String)
//Then downloaded the images to show on view
URLSession.shared.dataTask(with: url! as URL, completionHandler: { (data, response, error) in
if error != nil {
print(error)
return
}
//Code to show images..
}).resume()
}
}
}
}
})
Can i receive feedback about this?

Resources