Storing data from firebase child key value pairs as an array - swift

How do I store key value pairs from firebase into an array? I've tried writing a code to send some data to firebase from a local array and noticed they are stored in such form:
notice how the 'medals' child are stored.
I'm trying to take a snapshot of the array from the 'medals' object and return it as an array in swift.
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").child(userID!).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user medals
self.identities3 = snapshot.value!["medals"] as! [String]
})
I know this is very crude, but would it work?
Thanks! Still pretty new to firebase and learning :)

Try this:
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").child(userID!).child("medals").observeSingleEventOfType(.Value, withBlock: { (snapshot) in
// Get user medals
self.identities3 = snapshot.value as! [String]
})

Consider changing your JSON structure to :-
Medals: {
Shield : true,
Tie : true
}
To retrieve:-
Swift 3
let array = [String]()
FIRDatabase.database().reference().child("users")child(FIRAuth.auth()!.currentUser!.uid).child("medals").observeSingleEvent(of: .value, with: {(snap) in
if let snapDict = snap.value as? [String:AnyObject]{
for each in snapDict{
print(each.key)
self.array.append(each.key)
}
}
})
Swift 2
let array = [String]()
FIRDatabase.database().reference().child("users")child(FIRAuth.auth()!.currentUser!.uid).child("medals").observeSingleOfEvent(.Value, withBlock: {(snap) in
if let snapDict = snap.value as? [String:AnyObject]{
for each in snapDict{
print(each.0)
self.array.append(each.0)
}
}
})

Related

Not able to read data from Firebase realtime database

I have stored the comments under a post in firebase realtime database. The problem i have is that when i try to parse out the data from firebase i get an error that says Unexpectedly found nil while unwrapping an Optional value. So for example if i try to pront the data stored under degree, i get this nil error. But when i print "comments" instead of the "degree" i successfully fetch the data. My database structure looks like this.
func obeserveComments() {
// get auto-id of post
let commentKey = self.keyFound
let postRef = Database.database().reference().child("posts").child(commentKey)
var tempComments = [Comments]()
postRef.observe(.value, with: {(snapshot) in
if let dict = snapshot.value as? [String:Any] {
if let comments = dict["comments"] as? [String:Any] {
let degree = comments["reply degree"] as! String
// let name = comments["reply name"] as! String
// let text = comments["reply text"] as! String
// let university = comments["reply university"] as! String
// let photoURL = comments["reply url"] as! String
// let url = URL(string: photoURL)
// let timestamp = comments["timestamp"] as! Double
print(degree)
}
}
})
}
The answer by #aytroncb is a good answer, I prefer to leave Firebase data 'Firebasy' as long as possible. In other words coverting to dictionaries looses ordering and and find code like this
[String: [String: [String: Any]]]
To be very hard to read.
I prefer
let snap = snapshot.childSnapshot("comments") //snap becomes a DataSnapshot
So my solution maintains the order and leverages .childSnapshot to leave data in it's DataSnapshot form.
func readPostComments() {
let postRef = self.ref.child("posts") //self.ref points to my firebase
postRef.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
print("postId: \(postSnap.key)")
let commentsSnap = postSnap.childSnapshot(forPath: "comments") //will be a DataSnapshot
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
print(" commentId: \(commentSnap.key)")
let replyDegree = commentSnap.childSnapshot(forPath: "reply_degree").value as? String ?? "No Degree"
let replyName = commentSnap.childSnapshot(forPath: "reply_name").value as? String ?? "No Name"
print(" degree: \(replyDegree) by: \(replyName)")
}
}
})
}
EDIT
For a single post, remove the top part of the code that reads in and iterates over all posts.
func readCommentsForOnePost() {
let postRef = self.ref.child("posts")
let postCommentRef = postRef.child("post_0")
postCommentRef.observeSingleEvent(of: .value, with: { snapshot in
print("postId: \(snapshot.key)")
let commentsSnap = snapshot.childSnapshot(forPath: "comments") //will be a DataSnapshot
let allComments = commentsSnap.children.allObjects as! [DataSnapshot]
for commentSnap in allComments {
print(" commentId: \(commentSnap.key)")
let replyDegree = commentSnap.childSnapshot(forPath: "reply_degree").value as? String ?? "No Degree"
let replyName = commentSnap.childSnapshot(forPath: "reply_name").value as? String ?? "No Name"
print(" degree: \(replyDegree) by: \(replyName)")
}
})
}
Its because firebase is returning your data like this
{
"MAKFW244kdL)Cw;1": [Array of data],
"LOPSw!35pa3flAL4": [Array of data],
"ALV34VR4_A6Vn1a": [Array of data]
}
So change your initial casting of snapshot.value to this:
if let dict = snapshot.value as? [String: [String: Any]]
then loop through that new dictionary like this:
for objectJson in dict.values {
if let comments = objectJson["comments"] as? [String: [String: Any]] {
for commentJson in comments.values {
let degree = commentJson["reply_degree"] as? String
}
}
}
Update
Just read through your post again and noticed your trying to access the comments directly with a key, your first going to need to provide the PostId. Then you can use the above code to loop through the objects
let postRef = Database.database().reference().child("posts").child(postID)
alternatively I believe you can have the comments returned as a normal list by doing something like this:
let postRef = Database.database().reference().child("posts").child("\(postID)/{id}")

How can i fetch specific data from firebase and store it in a dictionary?

I'm trying to fetch data from my firebase database, such that i can store it in a form of dictionary which is a type [String: [Any]] where key is the unique id and the value is a type of array which has the data stored under uniqueID->Question.
func getData(currUser: String, completion: #escaping (([String : [Any]]) -> ())) {
var newArray = [String : [Any]]()
let ref = Database.database().reference(fromURL: "MYURL").child("users/\(currUser)/Questions").observeSingleEvent(of: .value, with: { (snap) in
let enumerator = snap.children
while let rest = enumerator.nextObject() as? DataSnapshot, let value = rest.value{
newArray.updateValue([value], forKey: rest.key)
}
completion(newArray)
})
}
this completion block gives me:
["-LlpbizBpQTXOQ6zv0zd": [{
Qusetion = (
Hello,
test,
kkkkkkkkkkk
);
}]]]
Instead how can i get
["-LlpbizBpQTXOQ6zv0zd": [Hello,test,kkkkkkkkkkk]]
You're converting the value to a string, while it's actually a JSON object. That's why the value in your dictionary is a JSON object.
To only get the question text under Qusetion (typo?), you'll need to loop over that child snapshot and collect the individual values. Something like:
var newArray = [String : [Any]]()
let ref = Database.database().reference(fromURL: "MYURL").child("users/\(currUser)/Questions").observeSingleEvent(of: .value, with: { (snap) in
let enumerator = snap.children
while let rest = enumerator.nextObject() as? DataSnapshot {
var values = [String]
let valueEnumerator = rest.childSnapshot(atPath: "Qusetion").children
while let valueRest = valueEnumerator.nextObject() as? DataSnapshot, let value = rest.value {
values.append(value)
}
newArray.updateValue([values], forKey: rest.key)
}
completion(newArray)
})

How do I get specific values from children in firebase using Swift 4?

My Firebase Database
More specifically, I have randomly generated children(Listings) and from those randomly generated Listings I would like to get the string value from the keys.
For example, if I wanted the Photo URL address, I would like to get the string value of the key "PhotoURL:".
Thank you in advance !
First you need to do is to import Firebase and then call a function from the Database class like so:
let ref = Database.database().reference().child("Listings")
You can call child recursively to go deeper into your tree
//.child("Listings").child("SomeListing").child("PhotoURL")
Then call observeSingleEvent to receive the values from firebase.
Your value is stored in the snapshot variable
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let listingsDictionary = snapshot.value as? [String: Any] else { return }
listngsDictionary.forEach({ (key, value) in
// Here you can iterate through it
})
}) { (err) in
print("Failed to fetch following listings:", err)
}
Here is the code to get child values from Listings. 
var ListArr = [ListModel]()
let ref = Database.database().reference().child("Listings")
ref.observe(.childAdded, with: { (snapshot) in
print(snapshot)
guard let dictionary = snapshot.value as? [String : AnyObject] else {
return
}
let Obj = ListModel()
Obj.UID = snapshot.key
Obj.PhotoURL = dictionary["PhotoURL"] as? String
self.ListArr.append(Obj)
}, withCancel: nil)
}
You can set up the model class
class ListModel: NSObject {
var UID:String?
var PhotoURL:String?
}

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.

Retrieve data stored by childByAutoID in firebase

In firebase i'm trying to retrieve data stored in the firebase realtime database by using the childByAutoID() to give the data a unique identifier but the problem is i'm not entirely sure how to achieve this?
func retData(){
rootRef.child("users").child(userID).ChildByAutoID().observeEventType(.Value){
(snap: FIRDataSnapshot) in
self.simpleLabel.text = snap.value?.description
}
}
Json data structure
-userID
-childByAutoID
-player1
-email
If your JSON structure is:-
-users
-childByAutoID
-playerID
-email
Use :-
rootRef.child("users").observeEventType(.Value, withBlock: {(snap) in
if let userDict = snap.value as? [String:AnyObject]{
for each in userDict as [String: AnyObject] {
let autoID = each.0
//Here you retrieve your autoID
rootRef.child("users").child(autoID).child("player1").observeEventType(.Value, withBlock: {(playersDict) in
if let playerDictionary = playerDict.value as? [String:AnyObject]{
let emailID = playerDictionary["email"] as! String
//print(emailID)
}
})
}
}
})