I am using Firebase and I have had no problems getting data in alphabetical order until recently. I never used queries, I always just used snapshots of data and sorted through them one-by-one. Recently, the data has not been always coming in alphabetical order in the snapVal. How do I make it so I get a snapVal of data sorted alphabetically, like it is in the snapshot from the database?
Real Example: there are 4 messages, id1-id4 (in that order). They contiain the message "1"-"4". The snapshot comes looking correct. But the snapVal (snapshot.value) looks like this:
["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}]
What the snapshot looks like:
["id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}]
To get the snapVal, I use this:
if let snapVal = snapshot.value as? [String: AnyObject] {
// Comes out of order..
}
To clarify:
Snapshot (this ends up coming out correct):
Snap (CHAT) {
id1 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
};
id2 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
};
id3 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
};
id4 = {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
};
}
This is the output for print(snapVal.keys)
inside if let snapVal = snapshot.value as? [String: AnyObject]
:
LazyMapCollection<Dictionary<String, AnyObject>, String>(_base: ["id2": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 2;
TIME = "8:12 PM";
}, "id4": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 4;
TIME = "8:12 PM";
}, "id1": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 1;
TIME = "8:12 PM";
}, "id3": {
DATE = "10/20/16";
"FIRST_NAME" = first;
ID = userID;
"LAST_NAME" = last;
MESSAGE = 3;
TIME = "8:12 PM";
}], _transform: (Function))
My Code:
self.firebase.child("Chats").child(chatID).queryOrderedByKey().observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
if let snapVal = snapshot.value as? [String: AnyObject] {
print(snapVal)
for c in snapVal {
print("checking Message as child")
let message = c.value["MESSAGE"] as? String
let fn = c.value["FIRST_NAME"] as? String
let ln = c.value["LAST_NAME"] as? String
let USER_ID = c.value["ID"] as? String
if let userID = USER_ID {
if let msg = message {
if let firstName = fn {
if let lastName = ln {
let username = "\(firstName) \(lastName)"
self.addMessage(userID, text: msg, name: username)
print("Message added! \nMessage Info:")
print("User ID: \(userID)")
print("text: \(msg)")
print("Username: \(username)")
} else {
print("LN did not pass")
}
} else {
print("FN did not pass")
}
} else {
print("Msg did not pass")
}
} else {
print("User ID did not pass")
}
}
}
})
Since you haven't shared the necessary code, I'll assume you're doing something along these lines:
ref!.queryOrdered(byChild: "text").observe(.value, with: { (snapshot) in
print("\(snapshot.value)")
})
When you execute a query on a Firebase location, the data is returned with information about the order of the items according to the query. When you observe a value event, the snapshot contains the keys, the values and the order of the children.
But when you convert request the snapshot.value
property, all information has to be converted into a dictionary. The keys and the values of each child survive this conversion, but the information on ordering is lost.
For this reason, you'll have to use the children
property of the snapshot to iterate over the children in the correct order:
ref!.queryOrdered(byChild: "text").observe(.value, with: { snapshot in
for child in snapshot.children {
print("child \(child)")
}
})
Solution: After very extensive searching and attempting, the problem still persisted that once the snapshot was converted to a snapVal (snapshot.value), the order often rearranged. My (working) solution:
for child in snapshot.children {
let child = child as! FIRDataSnapshot
if let childVal = child.value as? [String: AnyObject] {
let childMessage = childVal["MESSAGE"] as! String
// more code for each child. This child might be a post of a sort, which you can access properties of in a way like I did in the line above
}
}
Process:
Loop through each child in snapshot
Convert the child to a FIRDataSnapshot so it is not an element
Get the value of the particular child to access properties from
Add in the respective code for the child following NSDictionary principles.
Why this solution is solid
Receiving snapshots in the proper order is very simple. The issue I faced was getting data in the correct order when I got the snapshot.value
. This solution fixes that because the values of each child are only accessed when looping through the children of snapshot, which is sorted. This leaves the order of children still in the control of the snapshot.
I also like the snapshot.value
approach by using [String: AnyObject]
because it is very close to the old functionality of Firebase implementation in Swift: Simple and very clean. I actually think that using NSDictionary in this way is really a way to save time in the long run because it is not verbose in any way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With