Retrieving multiple firebase nodes swift - swift

Im retrieving data from a firebase backend which is below. My JSON structure has 2 child notes from my understanding With the code in my view did load, i can access the users node and i can print the "email" & "provider" -
However, my main goal is to actually access the 'planits' node and get the "images" & "planit" details. I am just pretty stuck on a way to implement that. I would appreciate any and all of the help provided. Thank you!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
refHandle = ref.observe(DataEventType.value, with: { (snapshot) in
let dataDict = snapshot.value as! [String: AnyObject]
print(dataDict)
})
let userID = Auth.auth().currentUser?.uid
ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
//Get user value
if snapshot.exists() == true {
for child in snapshot.children {
let value = snapshot.value as? NSDictionary
let EmailString = value!["email"] as! String
self.userEmail.append(EmailString)
print(self.userEmail)
// BELOW IS MY FAILED ATTEMPT AT ACCESSING THE 'planits' node - Nothing Prints
let image = value!["images"] as! String
print(image)
}
}
}) { (error) in
print(error.localizedDescription)
}

Related

Firebase: cannot retrieve children if they are less than the specified number in queryLimited

I have the following function that gets invoked when a user scrolls conversation tableview, it works well but if the remaining children are less than the specified number it retrieves none! What is more interesting is that those values appear in print(snapshot.value) but not in print(child). How can I get all nodes even if they are less than the specified number?
Thank you.
func fetchBatch(betweenUser userID: String, fromTimestamp: Double , completion: #escaping([Message]) -> ()){
guard let currentUID = Auth.auth().currentUser?.uid else { return }
var messages = [Message]()
REF_MESSAGES.child(currentUID).child(userID).queryOrdered(byChild: "timestamp").queryEnding(atValue: fromTimestamp).queryLimited(toLast: 20).observeSingleEvent(of: .value) { snapshot in
print(snapshot.value)
for child in snapshot.children {
print(child)
if let childSnapshot = child as? DataSnapshot {
guard let dictionary = childSnapshot.value as? [String: AnyObject] else {return}
let message = Message(dictionary: dictionary)
messages.append(message)
}
}
return completion(messages)
}
}
Just a guess but you may have a problem with your data structure.
That guard statement
guard let dictionary = childSnapshot.value as? [String: AnyObject] else {return}
will prevent the messages array from being fully populated when it fails.
My guess is your retrieving say, 10 child notes, then as the code iterates over them, at some point the guard statement fails due to the structure. For example a [Int: Any] instead of a [String: Any]
The end result is that not all of the child nodes are not added to the array - which in turn means there's less elements in the array than was was actually retrieved from Firebase.

Accessing firebase database returns nil swift

I want to access database through this code :
let ref = Database.database().reference()
ref.observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
print(value)
}) { (error) in
print(error.localizedDescription)
}
Here is my database :
The value printed is nil. I don't understand why...
What I tried :
I printed the value of the snapshot which is a dictionary.
I think the problem is casting the data as? NSDictionary
Can you try:
let value = snapshot.value as? [String:String]

I cant see values from firebase swift

Screen Shot 2019-04-01 at 4.45.08 PMenter image description hereI want to get the value from firebase that is stored I want to print it into a text label,
func fetchData(){
var ref: DatabaseReference!
ref = Database.database().reference()
guard let currentUid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(currentUid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String , AnyObject> else {return}
let uid = snapshot.value
let user = User(uid:uid as! String, dictionary: dictionary)
self.user = user
}) { (error) in
print(error.localizedDescription)
}
}
This is my another code to set the text label
func fetchData(){
var ref: DatabaseReference!
ref = Database.database().reference()
guard let currentUid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child("users").child(currentUid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? Dictionary<String , AnyObject> else {return}
let uid = snapshot.value
let user = User(uid:uid as! String, dictionary: dictionary)
self.userNameLabel.text = user.username
self.user = user
print(snapshot)
}) { (error) in
print(error.localizedDescription)
}
}
extra code to understand what I am doing
// user info stored
let userID = Auth.auth().currentUser?.uid
let userData = ["userName": userName,
"userAge ": userAge] as [String? : Any]
let values = [userID: userData]
let ref = Database.database().reference()
ref.child("users").childByAutoId().setValue(values)
}
I think you should use callbacks to communicate asynchronously with your controller.
In your example you get the uid by using "snpashot.value" but you should take the key of your dictionary instead.
Here is a similar example :
///Function that returns as callback the user stored in Firebase with a certain id.
func getUserFor(id: String, callback: #escaping (Bool, User?) -> Void) {
//Get the user in Firebase "user" collection with the specific id.
ref.child(Constants.userKey).child(id).observeSingleEvent(of: .value, with: { (userSnapshot) in
guard let userDictionnary = userSnapshot.value as? [String:Any] else { return callback(false, nil) }
let userId = userSnapshot.key
let userEmail = userDictionnary[Constants.emailKey] as? String
let user = User(id: userId, email: userEmail)
return callback(true, user)
}) { (error) in
print(error.localizedDescription)
return callback(false, nil)
}
}
I have found the answer I wasn't setting the user stored info in the firebase the right way.
let userID = Auth.auth().currentUser?.uid
let userData = ["userName": userName,
"userAge ": userAge] as [String? : Any]
let ref = Database.database().reference()
ref.child("users/\(userID ?? "")").setValue(userData)
}
//ref.child("users/(userID??"")").setValue(userData) // this was the error

Accessing nested key-value pairs in swift

I am trying to access the value of the key 1. Here is my Firebase diagram:
And here is my code:
#IBAction func ridefinder(_ sender: Any) {
let ref = Database.database().reference()
ref.child("name/hi").observeSingleEvent(of: .value) { (snapshot) in
print(snapshot.value as? [String:Any])
}
When I run this it prints nil, however when I change it slightly to this:
#IBAction func ridefinder(_ sender: Any) {
let ref = Database.database().reference()
ref.child("name").observeSingleEvent(of: .value) { (snapshot) in
print(snapshot.value as? [String:Any])
}
it prints both sets of key-value pairs inside.
How do I just access the value of the key hi inside name?
Try:
let ref = Database.database().reference()
ref.child("name").observeSingleEvent(of: .value) { (snapshot) in
if let value = snapshot.value as? [String:Any], let hi = value["hi"] as? String {
print(hi)
}
}
Values inside database references are accessed by using snapshot.value and being casted as [String: Any]. And then you find your desired values inside dictionary like always accessing them as dictionary["key"].

How to stop observe

I have this code for retrieving data from Firebase database. The code works fine, but it retrieves the same data multiple times.
How do I stop observe so that the data will only be called once
My code
self.eventGalleryImage.child("event")
.child(self.eventName.text!)
.child("EventImages")
.observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for child in snapshots {
if let dict = child.value as? Dictionary<String, Any> {
if let userGallery = dict["Text"] as? String {
self.postsFindGallery.insert(galleryStruct(gallery: userGallery), at: 0)
self.collectionView.reloadData()
}
}
}
}
})
A lesson to be learnt. Do all you can to avoid using for loops when observing data. This is what you'll need to do to get all of the data inside that database path ONCE:
self.eventGalleryImage.child("event")
.child(self.eventName.text!)
.child("EventImages")
.observe(.childAdded, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String: AnyObject] else { return }
if let userGallery = dictionary["Text"] as? String {
self.postsFindGallery.insert(galleryStruct(gallery: userGallery), at: 0)
self.collectionView.reloadData()
}
}, withCancel: nil)
You may also want to try:
DispatchQueue.main.async {
self.collectionView.reloadData()
}