Retrieving data list from Firebase [Swift] - swift

I'm trying to get a String array with the list of all usernames, but for some reason my code isn't working. Output should be [sean, yuh]
Database.database().reference().child("usernames").observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let uid = snap.childSnapshot(forPath: "username")
self.array.append(uid1)
}
}

Your uid1 is not declared in the code you shared, and definitely not the value of the username property in the JSON. In addition, you'll want to get the value of the child snapshot. So combines:
Database.database().reference().child("usernames").observeSingleEvent(of: .value, with: { (snapshot : DataSnapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let uid = snap.childSnapshot(forPath: "username")
self.array.append(uid.value)
}
}

Related

Getting the value from Firebase and appending it to an array in Swift?

I just started learning Swift and I am trying to read the value from every child in the real-time-firebase. I would like to save it as a string in an array. This is what I have tried:
self.ref.child("someId/name").observe(.value) { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value
self.preis.append(value as! String)
}
}
But I am always getting the error: Thread 1: signal SIGABRT
in this line: self.preis.append(value as! String)
I tried
self.ref.child("someId/name").observe(.value) { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
let value = snap.value
self.preis.append(snapshot.value as! String)
}
}
And now I get the value like this: Optional(...)
You can try
self.ref.child("someId/name").observe(.value) { snapshot in
let res = snapshot.value as! String
print(res)
self.preis.append(res)
}

Getting values from Firebase snapshot in Swift

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.

Swift Firebase - trying to retrieve more than one set of data in a function to count the number of entries

I have a problem trying to retrieve two sets of data from Firebase, in one function. The results from this retrieve will be used to update a progress bar, after the retrieve (otherwise 'zero' values) so this 'progress bar' function is also included in the Firebase function. To clarify further, I am trying to get the count of entries for 'user-posts', and 'user-plans' from the Firebase Db:-
The code for the function looks like this (and then I'll let you know what the issue is!):-
func firebaseRetrieve() {
guard let uid = Auth.auth().currentUser?.uid else {return}
let planRef = DB_BASE.child("user-plan").child(uid)
planRef.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
self.totalPlans.append(key)
self.planCount = Double(self.totalPlans.count)
let postRef = DB_BASE.child("user-posts").child(uid)
postRef.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snaps = child as! DataSnapshot
let keys = snaps.key
self.totalPosts.append(keys)
self.postCount = Double(self.totalPosts.count)
self.fraction = self.postCount / self.planCount
//THIS IS WHERE I INPUT ANOTHER FUNCTION TO PASS THE VALUE OF 'FRACTION' INTO, THAT THNE DETERMINES THE PROGRESS BAR
}
})
}
})
THE ISSUE: The current count of 'user-plan' is 18. The current count of 'user-posts' is 14. So the fraction should equal 0.77 (78%). But, the count of 'user-posts' seems to be reiterated 18 times, so the count is 252 (i.e. 14 * 18)!! I've tried all sorts to fix it over the past 3 days, but always the same result.
Any ideas greatly received, and will stop me swearing at the wife......
you can use snapshot.childrenCount to get the count of the snapshot children , and you need to move your calculation for fraction outside the loop
checkout this code
func firebaseRetrieve()
{
guard let uid = Auth.auth().currentUser?.uid else {return}
let planRef = DB_BASE.child("user-plan").child(uid)
planRef.observeSingleEvent(of: .value, with:
{
(snapshot) in
self.planCount = snapshot.childrenCount;
for child in snapshot.children
{
let snap = child as! DataSnapshot
let key = snap.key
self.totalPlans.append(key)
}
let postRef = DB_BASE.child("user-posts").child(uid)
postRef.observeSingleEvent(of: .value, with:
{
(snapshot) in
self.postCount = snapshot.childrenCount;
for child in snapshot.children
{
let snaps = child as! DataSnapshot
let keys = snaps.key
self.totalPosts.append(keys)
}
self.fraction = self.postCount / self.planCount;
print("fraction = \(self.fraction)")
})
});
}

Swift Firebase Get the parent value from children

I have this database structure:
I am trying to get the node value (for example: -KzjZJvEQRBlRG8m2RxO) if the objectId value is equal to a specific value.
Let me give you an example:
if the object id is equal to "-Kzx6b-w3cbE_3e1MwWr" then i would like to get the node value (-Kzx6bVxJHq0HgDjkhH8) so i can delte the record.
I tried to do it like so:
let query = Api.Notification.NOTIFICATION_REF.queryOrdered(byChild: "objectId").queryEqual(toValue: id)
query.observeSingleEvent(of: .value, with: { (snapshot) in
for snap in snapshot.children {
print (snap.key)
}
However i get no value in the print statement Actually is seem not to enter at all the for cycle.
Is there a way to achieve this?
Thank you!
-----UPDATE
Would a solution like this affect the speed if i get many records?
Api.Notification.NOTIFICATION_REF.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let key = snap.key
Api.Notification.NOTIFICATION_REF.child(key).observeSingleEvent(of: .value, with: { (userid) in
for subChild in userid.children {
let subSnap = subChild as! DataSnapshot
let subKey = subSnap.key
//get the value here
}
})
}
})
Use snap.ref.parent?.key
Example:
query.observe(.value, with: { snap in
guard let text = snap.value as? String else { return }
print("snap parent key: \(snap.ref.parent?.key)")
}

swift firebase nested children dictionary delete

firebase structure
In the firebase structure you can see i have to delete specific user (currentUserId) in all the groups:
it's what i try to do:
###########################UPDATED###################################
let groupsRef = self.root.child("groups")
groupsRef.observeSingleEvent(of: .value, with: { snapshot in
for groupChild in snapshot.children {
let groupSnap = groupChild as! DataSnapshot
var dict = groupSnap.value as! [String: Any]
let uid = dict["utenti"] as! [String: Bool]
for each in uid {
if each.key == self.currentUserID{
print(each.key)
//i now need a way to remove this key:value
}
}
}
})
I'm new so i'm not able to go further in extracting every key of ditcionary, than i will compare to the one i have to delete and if it's the same i will delete.
Can someone help?
let groupsRef = self.root.child("groups")
groupsRef.observeSingleEvent(of: .value, with: { snapshot in
for groupChild in snapshot.children {
let groupSnap = groupChild as! DataSnapshot
let groupKey = groupSnap.key
//added a groupKey to track the id of each group
var dict = groupSnap.value as! [String: Any]
var uid = dict["utenti"] as! [String: Bool]
//then for each key:value in uid check if is there a key = to currentuserID
for each in uid {
if each.key == self.currentUserID{
uid.removeValue(forKey: each.key)
//here you remove currentuserId from the dictionary and below
//finally you set back the new value of the dictionary without currentuserId
self.root.child("groups").child(groupKey).child("utenti").setValue(uid)
}
}
}
})
you can use
for (key, value) in uid {
}
to loop over a dictionary.
But really, looking in the official documentation of swift would give you the right answer...
let groupsRef = self.root.child("groups")
groupsRef.observeSingleEvent(of: .value, with: { snapshot in
for groupChild in snapshot.children {
let groupSnap = groupChild as! DataSnapshot
for subGroupChild in groupSnap.children {
//Here you need to remove that specific user if condition match
//specificUserUID is that user's id that user to be deleted
if let snapref = subGroupSnap as! DatabaseReference {
snapref.queryOrdered(byChild: "utenti").queryEqual(toValue: specificUserUID).observe(.childAdded, with: { (snapshot) in
snapshot.removeValue(completionBlock: { (error, reference) in
if error != nil {
print("There has been an error:\(error)")
}
})
})
}
}
}
})
Your code will go like above you just need find thaat user by user ID and delete that particular snapshot.