facing Issue in parsing in swift3 - swift

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

Related

Get data from firestore and assign it to an array of dictionaries

I am trying to get data from firestore collection and assign it to an array of dictionaries. for this part of the code below... i get the error "Cast from 'QuerySnapshot?' to unrelated type '[[String : Any]]' always fails" and the console prints "is not working".
guard let snap = snapshot as? [[String:Any]] else {
print("is not working")
completion(.failure(DatabaseError.failedToFetch))
return
}
Here is the full code.
// fetches and returns all conversations for the user with passed in uid
public func getAllConversations(for uid: String, completion: #escaping(Result<[Conversation], Error>) -> Void) {
print("fetching all convos")
//NEW
let db = Firestore.firestore()
let CurrentUser = Auth.auth().currentUser?.uid
let ListRef = db.collection("users").document(CurrentUser!).collection("conversations")
// fetch the current users convo list
ListRef.getDocuments { snapshot, error in
if let err = error {
debugPrint("Error fetching documents: \(err)")
} else {
guard let snap = snapshot as? [[String:Any]] else {
print("is not working")
completion(.failure(DatabaseError.failedToFetch))
return
}
print("is working")
let conversations: [Conversation] = snap.compactMap({ dictionary in
guard let id = dictionary["id"] as? String,
let name = dictionary["name"] as? String,
let otherUserUID = dictionary["other_user-uid"] as? String,
let latestMessage = dictionary["latest-message"] as? [String:Any],
let date = latestMessage["date"] as? String,
let message = latestMessage["message"] as? String,
let isRead = latestMessage["is-read"] as? Bool else {
return nil
}
//save other user ID to a global var
self.test = otherUserUID
//assign data into an array of dictionaries
let latestConvoObject = LatestMessage(date: date, text: message, isRead: isRead)
return Conversation(id: id, name: name, otherUserUid: otherUserUID, latestMessage: latestConvoObject)
})
completion(.success(conversations))
}
}
}
There are a numbers of way to read that data, and the process can be simplified by conforming objects to the codable protocol but let me provide a straight forward example. I don't know what your Conversation object looks like so here's mine
class ConversationClass {
var from = ""
var to = ""
var msg = ""
var timestamp = 0
convenience init(withDoc: DocumentSnapshot) {
self.init()
self.from = withDoc.get("from") as? String ?? "no from"
self.to = withDoc.get("to") as? String ?? "no to"
self.msg = withDoc.get("msg") as? String ?? "no msg"
self.timestamp = withDoc.get("timestamp") as? Int ?? 0
}
}
and then here's the the code that reads in all the conversation documents from a Collection, stores each in a ConversationClass object, puts those in an array and returns it through an escaping completion handler
func getConversations(completion: #escaping( [ConversationClass] ) -> Void) {
let conversationCollection = self.db.collection("conversations")
conversationCollection.getDocuments(completion: { snapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = snapshot?.documents else { return }
var convoArray = [ConversationClass]()
for doc in docs {
let convo = ConversationClass(withDoc: doc)
convoArray.append(convo)
}
completion(convoArray)
})
}

Retrieving multiple data in Firebase with 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)
}
}
}
}

Can't get node of firebase children

Hi there i'm newest in swift. I am working with a firebase database with at 2 layer of hierarchy as well as many children for each node. I got 1st layer (descript, enddata and other), but i stll can't get the news node. Is in 3 to 5 random keys. I sow many issues but still not have issue for me.
I'm understand i'm doing some wrong but what?
The Firebase is:
i need retreat the news child
struct is
struct ICONews {
let ICOId: String
let news1: String
let news2: String
let news3: String
init?(ICOId: String, dict: [String: Any] ) {
self.ICOId=ICOId
guard let news1 = dict[""] as? String,
let news2 = dict[""] as? String,
let news3 = dict[""] as? String
else { return nil }
self.news1 = news1
self.news2 = news2
self.news3 = news3
}
}
struct NewsSnapShot {
let posts: [ICONews]
init?(with snapshot: DataSnapshot) {
var posts = [ICONews] ()
guard let snapDict = snapshot.value as? [String: [String: Any]] else { return nil }
for snap in snapDict {
guard let post = ICONews (ICOId: snap.key, dict: snap.value) else {continue}
posts.append(post)
}
self.posts=posts
}
}
class of DataBase
class DatabaseService {
static let shared = DatabaseService()
private init(){}
let ICOReference = Database.database().reference()
}
and retreat method
DatabaseService.shared.ICOReference.child("news").observe(DataEventType.value, with: { (snapshot) in
guard let postsSnapShot = ICOSnapShot(with: snapshot) else {return}
})
done
Database.database().reference().observeSingleEvent(of: .value, with: {(snapshot) in
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
let values = (rest as! DataSnapshot).value as? NSDictionary
let enumeratorMap1 = (rest as! DataSnapshot).children
while let rest2 = enumeratorMap1.nextObject() as? DataSnapshot {
let valuesMap1 = (rest2 as! DataSnapshot).value as? NSDictionary
if (rest2 as! DataSnapshot).key == "news" {
print(rest2.value)
}
}
}
})
Make the the Firebase Api call like
Database.database().reference().child("users").child(userID).observe(.childAdded, with: { (snapshot) in
if snapshot.exists() {
let receivedMessage = snapshot.value as! [String: Any]
let name = receivedMessage["name"] as? String ?? ""
let id = receivedMessage["id"] as? Double ?? 0.0
let profileurl = receivedMessage["url"] as? String ?? ""
completion(User(name: name, id: id, url: url))
} else {
failure()
}
})

Ambiguous Use of Subscript (Swift 3)

I am using the subscript in the following code incorrectly for this Firebase data pull, but I can't figure out what I am doing wrong. I get an error of Ambiguous use of subscript for the let uniqueID = each.value["Unique ID Event Number"] as! Int line.
// Log user in
if let user = FIRAuth.auth()?.currentUser {
let uid = user.uid
// values for vars sevenDaysAgo and oneDayAgo set here
...
let historyRef = self.ref.child("historyForFeedbackLoop/\(uid)")
historyRef.queryOrdered(byChild: "Unix Date").queryStarting(atValue: sevenDaysAgo).queryEnding(atValue: oneDayAgo).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("user data not found")
}
else {
if let snapDict = snapshot.value as? [String:AnyObject] {
for each in snapDict {
// Save the IDs to array.
let uniqueID = each.value["Unique ID Event Number"] as! Int
self.arrayOfUserSearchHistoryIDs.append(uniqueID)
}
}
else{
print("SnapDict is null")
}
}
})
}
I tried to applying what I learned from this post, but I couldn't figure out what I am missing because I thought I was letting the compiler know what type of dictionary it is with the "as? [String:AnyObject]"
Any thoughts or ideas would be greatly appreciated!
My preferred way of dealing with data is to unwrap the FIRDataSnapshot as late as possible.
ref!.observe(.value, with: { (snapshot) in
for child in snapshot.children {
let msg = child as! FIRDataSnapshot
print("\(msg.key): \(msg.value!)")
let val = msg.value! as! [String:Any]
print("\(val["name"]!): \(val["message"]!)")
}
})
Taking Frank's feedback into account, here is the actual working code I used that follows that approach in case it's helpful.
// Log user in
if let user = FIRAuth.auth()?.currentUser {
let uid = user.uid
// values for vars sevenDaysAgo and oneDayAgo set here
...
let historyRef = self.ref.child("historyForFeedbackLoop/\(uid)")
historyRef.queryOrdered(byChild: "Unix Date").queryStarting(atValue: sevenDaysAgo).queryEnding(atValue: oneDayAgo).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("user data not found")
}
else {
for child in snapshot.children {
let data = child as! FIRDataSnapshot
let value = data.value! as! [String:Any]
self.arrayOfUserSearchHistoryIDs.append(value["Unique ID Event Number"] as! Int)
}
}
})
}

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