Retrieving multiple data in Firebase with Swift - swift

Here is the database
I'm trying to append isDisable to an array
What i've come so far:
func retrieving(){
Database.database().reference().child("ServingHours/\(choosenDate)").observeSingleEvent(of: .value, with: {(snapshot) in
if let eachDict = snapshot.value as? NSDictionary{
for each in eachDict{
print(each.value)
}
}
}, withCancel: {(Err) in
})
}
with the result in console:
{
isDisable = false;
numberOfRegistration = 0;
}
{
isDisable = false;
numberOfRegistration = 0;
}
{
isDisable = false;
numberOfRegistration = 0;
}
{
isDisable = false;
numberOfRegistration = 0;
}
From this, I don't know what to do to get a specific value from each.value

You're retrieving your specific dates objects which have 2 items within them (isDisable and numberOfRegistration). When you retrieve them from Firebase, you're type casting them into NSDictionary using "as?".
Your values seem to be in String format, therefore, you can retrieve them from the NSDictionary using:
let isDisabled = eachDict["isDisable"] as? String
let numberOfRegistration = eachDict["numberOfRegistration"] as? String
You can also directly set your values in Firebase to be a Bool or Int and you can typecast your retrieved objects into Bool (isDisable) and Int (numberOfRegistration). But it looks like they are currently Strings, so your code would like this:
func retrieving(){
Database.database().reference().child("ServingHours/\(choosenDate)").observeSingleEvent(of: .value, with: {(snapshot) in
if let eachDict = snapshot.value as? NSDictionary{
let isDisabled = eachDict["isDisable"] as? String
let numberOfRegistration = eachDict["numberOfRegistration"] as? String
print(isDisabled)
print(numberOfRegistration)
}
}, withCancel: {(Err) in
})
}
Also, if you want to retrieve a value directly, then you don't need to use an NSDictionary. You can just directly cast that value you retrieve into whatever type of object you have. For example, say you want to retrieve your "isDisable" value directly:
func retrieving(){
Database.database().reference().child("ServingHours/\(choosenDate)").child("isDisable").observeSingleEvent(of: .value, with: {(snapshot) in
if let isDisable = snapshot.value as? String{
print(isDisable) }
Check out the Firebase official documentation for Swift:
https://firebase.google.com/docs/database/ios/read-and-write

You need to cast to a dictionary once again (and don't use NSDictionary)
if let eachDict = snapshot.value as? [String: AnyObject]{
for each in eachDict {
if let innerDict = each as? [String: AnyObject] {
//innerDict now contains isDisable and numberOfRegistration
if let isDisable = innerDict["isDisable"] as? String
print(isDisable)
}
if let numberOfRegistration = innerDict["numberOfRegistration"] as? String {
print(numberOfRegistration)
}
}
}
}

Related

Cant fetch from Firebase Realtime Database

I don't know why cant find how get friends Ids.
her is my code:
func fetchUsers() {
let ref = Firebase.Database.database().reference()
guard let userId = Auth.auth().currentUser?.uid else { return }
let userID = userId
ref.child("Users").child(userID).observe(.childAdded) { (snapshot) in
print("snapshot...\(snapshot)")
let user = User()
if let dictionary = snapshot.value as? [String:AnyObject]{
user.currentUserFriends = dictionary["Friends"] as? String
print("dictionary...\(user.currentUserFriends ?? "no value")")
}
}
}
and my tree from firebase is Users-Uid-Friends-friendID-true.
Solved!
ref.child("Users").child(userID!).child("Friends").observeSingleEvent(of: .value) { (snapshot) in
print("snapshot...\(snapshot)")
let dic = snapshot.value as! NSDictionary
for (key,value) in dic{
let friendsID = key
let friendBool = value
print("key is \(friendsID) and value is \(friendBool)")
let user = User()
user.currentUserFriends = key as? String
}
}

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}")

Retrieve firebase data from swift

I'm trying to retrieve data from a Firebase RealTime database, in order to put it on a list which will be used to display data on a TableView.
My problem is that even if I get some data, I haven't enough knowledge to access on arrays and other swift objects. Perhaps, I'm not using the good way to do what I want.
Here is an example of a row on Firebase :
Here is a function written in Swift in which I'm trying to build a list for each row object.
func displayStationsUsingSearch(){
let station = self.stationName
let CP = Int(self.searchedCP!)
// create searchRef or queryRef you name it
let stationsRef = Database.database().reference().child("Stations")
stationsRef.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
/*if snapshot.value is NSNull {
print("not found")
} else {
// yes we got the user
let id = snapshot.value as! Int
}*/
for child in snapshot.children {
stationsRef.queryOrdered(byChild: "marque")
.queryEqual(toValue: "TOTAL ACCESS")
.observe(.value, with: { snap in
if let dict = snap.value as? [String: AnyObject] {
/*self.stationItem!.nomStation = dict["nomStation"] as! String
self.stationItem!.adresse = dict["adresse"] as! String
self.stationItem!.codePostal = dict["codePostal"] as! String
self.stationItem!.ville = dict["ville"] as! String
self.stationItem!.marque = dict["marque"] as! String
self.stationItem!.pays = dict["pays"] as! String
self.stationItem!.commentaire = dict["commentaire"] as! String
self.stationItem!.coordGPS = dict["coordGPS"] as! String*/
print(dict["nomStation"] as! String)
}
})
}
})
}
The lldb on Xcode workspace displays that :
Printing description of child:
Snap (-LdA6X8CfNY3bsPni31U) {
"DIESEL EXCELLIUM" = 0;
"DIESEL ULTIMATE" = 0;
GAZOLE = 0;
GPL = 0;
SP95 = 0;
"SP95 E10" = 0;
SP98 = 0;
SUPER = 0;
adresse = "RN1 Direction Moisselles";
codePostal = 95570;
commentaire = "";
coordGPS = "";
createdAt = "31/07/2018";
heureDebut = "";
heureFin = "";
id = 0;
marque = ESSO;
modifiedAt = "23/04/2019 18:53";
nomStation = "ESSO Moisselles";
pays = "";
saufJour = "";
services = "";
typeRoute = "";
ville = Moisselles;
}
(lldb)
Could you please help me to retrieve data on a list that I could append to display data on tableview ? Thank you.
Try something like that:
Database.database().reference()
.child("Stations").
observeSingleEvent(of: .value, with: { (snapshot) in
guard let value = snapshot.value as? [String: Any] else {
return
}
var stations = [Station]()
for (key, value) in values {
guard let station = value as? [String: Any],
let adresse = station["adresse"] as? String,
let codePostat = station["codePostat"] as? String else {
continue
}
stations.append(Station(adresse: adresse, codePostat: codePostat))
}
// if you have some completion return retrieved array of stations
completion(stations)
})
struct Station {
private let adresse: String
private let codePostat: String
init(adresse: String, codePostat: String) {
self.adresse = adresse
self.codePostat = codePostat
}
}
You can use a swift Class Instead.
Swift Object:
import Foundation
class FirebaseTransactionData : NSObject{
var customer : FirebaseTransactionDataCustomer!
var driver : FirebaseTransactionDataCustomer!
var status : String!
init(fromDictionary dictionary: [String:Any]){
status = dictionary["status"] as? String
if let customerData = dictionary["customer"] as? [String:Any]{
customer = FirebaseTransactionDataCustomer(fromDictionary: customerData)
}
if let driverData = dictionary["driver"] as? [String:Any]{
driver = FirebaseTransactionDataCustomer(fromDictionary: driverData)
}
}
}
class FirebaseTransactionDataCustomer : NSObject{
var lat : Double!
var longField : Double!
init(fromDictionary dictionary: [String:Any]){
lat = dictionary["lat"] as? Double
longField = dictionary["lng"] as? Double
}
}
Firebase Method
ref.observe(DataEventType.value, with: { (snapshot) in
let value = snapshot.value as? [String:Any]
let datt = FirebaseTransactionData(fromDictionary: value!)
print("snapshot \(datt.status!)")
print("snapshot \(datt.customer.lat!)")
})

facing Issue in parsing in swift3

I am trying to parse the emergency data in into emergency struct but it never statifies the condition and get into else case.Here is my code and structure.Some thing i have written woring in first line.
if let emergencyDict = snapshotValue["emergency"] as? [String:[String:Any]]{
for (emerId, emerData) in emergencyDict {
let emer = Emergency.init(emergency: emerData as NSDictionary)
emergency.append(emer)
}
}
else{
let emer = Emergency.init(emerg: "" as AnyObject)
emergency.append(emer)
}
struct Emergency{
var emer_id: String
var emer_name: String
var emer_phoneNo: String
init(emergency: NSDictionary) {
if emergency.object(forKey: "id") != nil {
emer_id = emergency.object(forKey: "id") as! String
}
else{
emer_id = ""
}
}
}
The problem you are having emergency as Array with type [Any] and if you remove the first object then you get Array of type [[String:Any]]. So try like this way.
if let array = snapshotValue["emergency"] as? [Any],
let emergencyArrar = Array(array.dropFirst()) as? [[String:Any]] {
print(emergencyArray)
for emergency in emergencyArray {
print(emergency)
}
}
You have written wrong in this line:
if let emergencyDict = snapshotValue["emergency"] as? [String:[String:Any]]{
It should be:
if let emergencyDict = snapshotValue["emergency"] as? [[String:Any]]{
This question should belong to query from firebase database.
// you have to get the children in emergency,
// then get the value(dictionary) of each child
ref.child("emergency").observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let keys = value?.allKeys // [1, 2, 3 ....]
for key in keys {
ref.child("emergency").child(key)..observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
// Here is your dictionary
}
}
}) { (error) in
print(error.localizedDescription)
}

Firebase 2, accesing child values in snapshot produces nulls

I've been attempting to utilize firebase's snapshots, but when I try to access specific children, the output is a null.
var ref = FIRDatabaseReference.init()
func loadData {
ref = FIRDatabase.database().reference(
ref.child("Posts").child(postId).observeSingleEventOfType(.Value, withBlock: { snapshot in
print(snapshot.value?["PostText"] as! String) // Optional(<null>)
print(snapshot)
for child in snapshot.children {
if child.childSnapshotForPath("PostText").value == nil {
self.postText.text = ""
} else {
self.postText.text = child.childSnapshotForPath("PostText").value as? String // Optional(<null>)
print(child.childSnapshotForPath("PostText").value)
}
}
})
}
Output of print(snapshot)
Snap (84844) {
Author = lGAV1KUhSCP8hnFiKY1N9lBPrmmst1;
CommentsCount = 1;
Group = 665555;
ImageUrl = "http://i.telegraph.co.uk/multimedia/archive/03589/Wellcome_Image_Awa_3589699k.jpg";
PostText = "I like cakeh, but theijijijijijij truth is, it's too sweet. So SOMETIMES I dont eat it, but i LIKE CAKE.";
}
It looks like your snapshot is a Dictionary. Then you have to cast it as a Dictionary:
func loadData {
ref = FIRDatabase.database().reference(
ref.child("Posts").child(postId).observeSingleEventOfType(.Value, withBlock: { snapshot in
print(snapshot.value?["PostText"] as! String) // Optional(<null>)
print(snapshot)
let dict = snapshot.value as! Dictionary<String, AnyObject>
if let author = dict["Author"] as? String, commentsCount = dict["CommentsCount"] as? Int, group = dict["Group"] as? Int {
print("author \(author) commentsCount \(commentsCount), group: \(group)")
}
})
}
Do the same for ImageUrl and PostText, they should be cast as String