i am attempting to retrieve a list of Posts ("Planits - in my apps language") from firebase. My goal is to display a specific users posts within a table view on their profile. I have written a function to retrieves posts and query them by a sender ID so that the user see's their posts on their profile. But at the end of the query when i try to print out the appended array, i keep getting an empty array, so i can not go further on to populate the table view. Please any suggestions on where i went wrong, attached is a screen shot of my firebase nodes and the function i wrote. thanks
func retrievePost(){
ref = Database.database().reference()
let myPlanitsRef = self.ref.child("planits")
let query = myPlanitsRef.queryOrdered(byChild: "senderId").queryEqual(toValue: "uid")
print(query)
query.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
for child in snapshot.children {
let snap = child as! DataSnapshot
print(DataSnapshot.self)
let dict = snap.value as! [String: Any]
let myPostURL = dict["images"] as! String
self.images.append(myPostURL)
}
//print(myPostURL) - DOES NOT PRING ANYTHING
//print(self.images) - DOES NOT PRING ANYTHING
}
}) { (error) in
print(error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
retrievePost()
print(images) // PRINTS []
Related
This is my data in firebase:
override func viewDidLoad() {
database.child("allOrdersTimeline1").observeSingleEvent(of: .value, with: { (snapshot) in
var mixedArray1 = [:] as [String : Double]
let salad = (snapshot.value)
let keyy = snapshot.key
let valuee = (snapshot.children.allObjects) //as [String : Double])
self.labelWhatLabel.text = ("\(valuee)")
print("There are \(snapshot.childrenCount) children found")
print("1")
print(keyy)
print("2")
print(valuee)
print("3")
print(salad)
print("4")
print("Ny test: \(mixedArray1)")
})
No matter what I try, I keep getting the full line (name and time) as such:
I can't figure out how to only get the hour/Double with out the name.
(by the way, im very new and this might be very dumb - My sincere apologies.
I think you might be looking for:
print(snapshot.childSnapshot(forPath:"Agerskov").value)
If you don't know the keys of the child nodes, you can loop over snapshot.children to access the child snapshots:
for child in snapshot.children {
let snap = child as! DataSnapshot
print(snap.key)
print(snap.value)
}
Also see these results when you search for [firebase-realtime-database][swift] loop over children.
I'm trying to allow a user to save data to a tableView using an alert that transfer data from the View Controller that the alert is in (CreatePlaylistVC) to another ViewController(CreatedPlaylistVC) that the tableView is in, saving for each specific account for a specific uid.
I've tried setting the value to the uid but this did work for me although it did save to the database under that specific uid.
CreatePlaylistVC
ref = Database.database().reference()
alert.addAction(UIAlertAction(title:"OK", style:.default, handler: {
action in
if let playlistName = alert.textFields?.first?.text {
let userID = Auth.auth().currentUser?.uid
self.ref?.child("PlaylistName").child(userID!).setValue(playlistName)
CreatedPlaylistVC
var ref:DatabaseReference?
var databaseHandle:DatabaseHandle?
override func viewDidLoad() {
//Set the firebase reference
ref = Database.database().reference()
//Retrieve the posts and listen fro changes
databaseHandle = ref?.child("PlaylistName").observe(.childAdded, with: { (snapshot) in
//Try to covert the value of the data to a string
let post = snapshot.value as? String
if let actualPost = post {
//Append the data to our playlistNameArray
self.playlistNameArray.append(actualPost)
//Reload the tableView
self.tableView.reloadData()
}
})
}
The expected results is to save the data only for the specified uid or currently logged in user. But it is saving for each user even though in the database it is saved to the right uid.
When using .childAdded for observe, it will go through every existing child under "PlaylistName" which in this case will be every user that has saved something.
Might have to reconsider your structure. Or use childByAutoID.
Edit: To use child by auto ID
// Your ["Name": Playlist] will get nested into an autogenerated child
self.ref?.child("PlaylistName").child(userID!).childByAutoID().setValue(["Name":playlistName])
//You will be listening for any new additions that your current user has made
databaseHandle = ref?.child("PlaylistName").child(Auth.auth().currentUser!.uid).observe(.childAdded, with: { (snapshot) in
// this loops through a list of playlist names your user creates
for child in snapshot.children{
let snap = child as! DataSnapshot
let value = snap.value as? Dict<String,Any>
let post = value["Name"] as! String
if let actualPost = post {
self.playlistNameArray.append(actualPost)
self.tableView.reloadData()
}
}
})
But my suggestion, if it suits your application, would be to change your data structure because it can keep your structure a lot flatter.
self.ref?.child(userID!).child("PlaylistName").setValue(playListName)
databaseHandle = ref?.child(userID!).observe(.childAdded, with: { (snapshot) in
let value = snapshot.value as? Dict<String,Any>
let post = value["PlaylistName"]
if let actualPost = post {
self.playlistNameArray.append(actualPost)
self.tableView.reloadData()
}
})
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
I have this database (see the link above with the image) and a code with a path, that leads to the destination using:
databaseReference.child("users").child(currentUser!.uid).child("todo-list")
Under the first node "users", the next level is a keyvalue for userID, and later there are more sub-levels "todo-list" etc.
I would like to fetch the data from all uid available. How can I make the query?
Here is the code:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
databaseReference = Database.database().reference()
currentUser = Auth.auth().currentUser
let todoListRef = databaseReference.child("users").child(currentUser!.uid).child("todo-list")
todoListRef.observe(DataEventType.value, with: { (DataSnapshot) in
self.itemsToLoad.removeAll()
let enumerator = DataSnapshot.children
while let todoItem = enumerator.nextObject() as? DataSnapshot
{
let item = todoItem.value as AnyObject
self.itemsToLoad.append(item)
}
self.itemsToLoad = self.itemsToLoad.reversed()
self.tableView.reloadData()
})
}
It's quite similar to the code you already have. Instead of observing /users/$uid, you observe the entire /users node. And then you add an extra loop in the closure, to iterate over all the users.
So:
let usersRef = databaseReference.child("users")
usersRef.observe(DataEventType.value, with: { (usersSnapshot) in
let userEnumerator = usersSnapshot.children
while let user = userEnumerator.nextObject() as? DataSnapshot {
let uid = user.key
let todoEnumerator = user.childSnapshot(forPath: "todo-list").children
while let todoItem = todoEnumerator.nextObject() as? DataSnapshot {
let item = todoItem.value as AnyObject
self.itemsToLoad.append(item)
}
}
})
The added while loops over the users, while the inner while loops over the todo's for each user. I removed the code related to the table view, since what you want to do there doesn't depend on Firebase.
Im successfully getting data from Firebase but I can't manage to push it into array to use. My database is as follows:
users
-Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2
-email : "mike#gmail.com"
-lists
-LJiezOzfDrqmd-hnoH-
-owner: Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2
-LJif-UgPgbdGSHYgjY6
-owner: Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2
shopping-lists
-LJh6sdBJtBCM7DwxPRy
-name: "weekly shopping"
-owner: "mike#gmail.com"
I have a home page after login that shows existing shopping lists on table if they exist. On viewDidLoad() I get shopping list IDs from the user and use those IDs as a reference to get details from shopping-lists.
However, I cant manage to save these data into an array as it gets deleted after closure. How can I do that in a clean way?
override func viewDidLoad() {
super.viewDidLoad()
SVProgressHUD.show()
tableView.allowsMultipleSelectionDuringEditing = false
// Sets user variable - must have
Auth.auth().addStateDidChangeListener { auth, user in
guard let user = user else { return }
self.user = User(authData: user)
// If new user, write into Firebase
self.usersRef.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.hasChild(self.user.uid) {
self.usersRef.child(user.uid).setValue(["email": user.email!])
}
})
// Get shopping lists data from "users/lists"
self.usersRef.child(user.uid).child("lists").observe(.value, with: { snapshot in
// Get list IDs
if snapshot.exists() {
if let result = snapshot.children.allObjects as? [DataSnapshot] {
for child in result {
self.listNames.append(child.key)
}
}
}
// Use list IDs - to get details
for item in self.listNames {
let itemRef = self.shoppingListsRef.child(item)
itemRef.observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let value = snapshot.value as? [String: Any] {
let name = value["name"] as? String ?? ""
let owner = value["owner"] as? String ?? ""
let shoppingList = ShoppingList(name: name, owner: owner)
self.items.append(shoppingList)
}
})
}
})
self.tableView.reloadData()
SVProgressHUD.dismiss()
}
}
(the question is a bit unclear so several parts to this answer to cover all possibilities. This is Swift 4, Firebase 4/5)
You don't really need to query here since you know which nodes you want by their key and they will always be read in the in order of your listNames array. This assumes self.listNames are the keys you want to read in.
for item in listNames {
let itemRef = shoppingListsRef.child(item)
itemRef.observe(.value, with: { (snapshot) in
if let value = snapshot.value as? [String: Any] {
let name = value["name"] as? String ?? ""
let owner = value["owner"] as? String ?? ""
print(name, owner)
}
})
}
Generally, queries are used when you are searching for something within a node - for example if you were looking for the node that contained a child name of 'weekly shopping'. Other than that, stick with just reading the nodes directly as it's faster and has less overhead. Keep reading...
I also removed the older NSDictionary and went with the Swift [String: Any] and modified your error checking
However, the real issue is reading that node with an .observe by .value. Remember that .value reads in all children of the node and then the children need to be iterated over to get each separate DataSnapshot. Also, .observe leaves an observer on the node notifying the app of changes, which I don't think you want. So this will answer the question as posted, (and needs better error checking)
for item in listNames {
let queryRef = shoppingListsRef
.queryOrdered(byChild: "name")
.queryEqual(toValue: item)
queryRef.observe(.value, with: { (snapshot) in
for child in snapshot.children { //even though there is only 1 child
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let name = dict["name"] as? String ?? ""
let owner = dict["owner"] as? String ?? ""
print(name, owner)
}
})
}
And the answer...
This is probably more what you want...
for item in listNames {
let queryRef = shoppingListsRef
.queryOrdered(byChild: "name")
.queryEqual(toValue: item)
queryRef.observeSingleEvent(of: .childAdded, with: { snapshot in
let dict = snapshot.value as! [String: Any]
let name = dict["name"] as? String ?? ""
let owner = dict["owner"] as? String ?? ""
print(name, owner)
})
}
note the .childAdded instead of .value which presents the snapshot as a single DataSnapshot and doesn't need to be iterated over and the .observeSingleEvent which does not leave an observer attached to each node.
Edit
Based on additonal information, it would be best too change the structure to this
shopping-lists
-LJh6sdBJtBCM7DwxPRy
-name: "weekly shopping"
-uid: "Wc1EtcYzZSMPCtWZ8wRb8RzNXqg2"
and then when the user logs in just query the shopping lists node for any uid that's theirs.