This is my data in Firestore:
My comment model:
class CommentModel {
var commentText: String?
var commentDate: NSObject?
var uid: String?
var username : String?
var profileImageUrl: String?
init(dictionary: [String: Any]) {
commentText = dictionary["commentText"] as? String
commentDate = dictionary["commentDate"] as? NSObject
uid = dictionary["uid"] as? String
username = dictionary["username"] as? String
profileImageUrl = dictionary["profileImageUrl"] as? String
}
}
My comments dictionary contains all documents of "comments".
XCode gives me the following suggestion, but I am unsure how to use it.
self.comments.sorted { (CommentModel, CommentModel) -> Bool in
}
How can I sort my dictionary by the commentDate?
You need
self.comments.sort { $0.commentDate < $1.commentDate }
make sure comments is declared as var , also cast it as a Date or String
commentDate = dictionary["commentDate"] as? Date
OR
commentDate = dictionary["commentDate"] as? String
Related
I have a UserModel:
class UserModel {
var uid: String?
var username : String?
var email: String?
var profileImageUrl: String?
var dateOfBirth: String?
var registrationDate: Int?
var isFollowing: Bool?
var accessLevel: Int?
var onlineStatus: Bool?
init(dictionary: [String : Any]) {
uid = dictionary["uid"] as? String
username = dictionary["username"] as? String
email = dictionary["email"] as? String
profileImageUrl = dictionary["profileImageUrl"] as? String
dateOfBirth = dictionary["dateOfBirth"] as? String
registrationDate = dictionary["userRegistrationDate"] as? Int
accessLevel = dictionary["accessLevel"] as? Int
onlineStatus = dictionary["onlineStatus"] as? Bool
}
}
And I also have a value like [12ih12isd89 : True]
I want to change the value "onlineStatus" for the user "12ih12isd89" to True and I thought the right way to do this is updateValue(:forKey:). But my class UserModel does not have updateValue(:forKey:).
How can I use this in my existing model?
Edit:
How I get the data:
func fetchAllUsers (completion: #escaping ([UserModel]) -> Void) {
let dispatchGroup = DispatchGroup()
var model = [UserModel]()
let db = Firestore.firestore()
let docRef = db.collection("users")
dispatchGroup.enter()
docRef.getDocuments { (querySnapshot, err) in
for document in querySnapshot!.documents {
let dic = document.data()
model.append(UserModel(dictionary: dic))
}
dispatchGroup.leave()
}
dispatchGroup.notify(queue: .main) {
completion(model)
}
}
To me it looks like you need to find the right object in the array and update the property
let dict = ["12ih12isd89" : true]
var model = [UserModel]()
if let user = model.first(where: {$0.uid == dict.keys.first!}) {
user.onlineStatus = dict.values.first!
}
Depending on what ["12ih12isd89" : true] really is you might want to change the access from dict.keys.first! that I used
If your value dictionary contains more than one user, you can use a for loop like this:
var model = [UserModel]()
//Some initalization ...
let values = ["12ih12isd89" : true]
for (k, v) in values {
model.filter({$0.uid == k}).first?.onlineStatus = v
}
Here is the output of "print(dict)"...
["2018-10-17 11:19:51": {
firstname = Brooke;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Alvarez;
message = hshahyzhshbsbvash;
username = poiii;
}]
["2018-10-17 11:20:31": {
firstname = Trevor;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Bellai;
message = hey;
username = br9n;
}]
["2018-10-17 11:20:44": {
firstname = Amy;
id = 40vI7hApqkfX75SWsqIR6cdt7xV2;
lastname = Ikk;
message = hey;
username = nine9;
}]
My code...
Database.database().reference().child("recent-msgs").child(uid!).observe(.childAdded) { (snapshot: DataSnapshot) in
if let dict = snapshot.value as? [String: Any] {
print(dict)
// Store data in user.swift model
let firstnameData = dict[0]["firstname"] as! String
let idData = dict["id"] as! String
let lastnameData = dict["lastname"] as! String
let messageData = dict["message"] as! String
let usernameData = dict["username"] as! String
let rankData = dict["rank"] as! String
let propicrefData = dict["propicref"] as! String
let convoinfo = RecentConvo(firstnameString: firstnameData, idString: idData, lastnameString: lastnameData, messageString: messageData, usernameString: usernameData, rankString: rankData, propicrefString: propicrefData)
self.recentconvos.append(convoinfo)
print(self.recentconvos)
self.tableView.reloadData()
}
}
I'm trying to retrieve the dictionary within the first dictionary which is the value to the key which is the date associate with it. For example: 2018-10-17 11:19:51. However I cannot use this exact string to call it because I must do this without the knowledge of that string.
I tried this:
let firstnameData = dict[0]["firstname"] as! String
But it returns an error:
Cannot subscript a value of type '[String : Any]' with an index of type 'Int'
The error noted above is showing up because you were trying to access the element at a certain position (0) from the dictionary. Dictionaries are not ordered lists, and hence won't have a fixed order of elements to be accessed.
The logged dictionary doesn't really look like a dictionary. Assuming that it is a dictionary, and its keys are the date strings, you can use the following code snippet to parse the dictionary.
class RecentConversation {
var id: String?
var firstName: String?
var lastName: String?
var message: String?
var username: String?
var rank: String?
var propicref: String?
init?(dictionary: [String: Any]?) {
guard let dict = dictionary else {
// Return nil in case the dictionary passed on is nil
return nil
}
id = dict["id"] as? String
firstName = dict["firstname"] as? String
lastName = dict["lastname"] as? String
message = dict["message"] as? String
username = dict["username"] as? String
rank = dict["rank"] as? String
propicref = dict["propicref"] as? String
}
}
Usage:
let dateStrings = dict.keys.sorted {
// Sort in chronological order (based on the date string; if you need to sort based on the proper date,
// convert the date string to Date object and compare the same).
//
// Swap the line to $0 > $1 to sort the items reverse chronologically.
return $0 < $1
}
var conversations: [RecentConversation] = []
for date in dateStrings {
if let conversation = RecentConversation(dictionary: (dict[date] as? [String: Any])) {
conversations.append(conversation)
}
}
You were all very helpful, so I would like to start off by saying thank you. I went ahead and applied the method that lionserdar explained. (.allKeys)
// Fetch Recent Messages
func fetchRecentMsgs() {
// Direct to database child
Database.database().reference().child("recent-msgs").child(uid!).observe(.childAdded) { (snapshot: DataSnapshot) in
if let dict = snapshot.value as? NSDictionary {
print(dict)
print(dict.allKeys)
let keys = dict.allKeys
for key in keys {
print(key)
if let nestedDict = dict[key] as? [String: Any] {
print(nestedDict)
let firstnameData = nestedDict["firstname"] as! String
let idData = nestedDict["id"] as! String
let lastnameData = nestedDict["lastname"] as! String
let messageData = nestedDict["message"] as! String
let usernameData = nestedDict["username"] as! String
Worked for me so I hope this will help others too!
I have chat app with possibility send messages one to one (fromId/toId). I want to upgrade it with chat rooms. How i can do that? What DB structure do i need for ChatingRoom? What else i need to do that?
My User.swift model:
import Foundation
import Firebase
class User: NSObject {
var id: String?
var name: String?
var login: String?
var email: String?
var profileImageUrl: String?
var role: String?
var isOnline: String?
init(dictionary: [String: AnyObject]) {
self.isOnline = dictionary["isOnline"] as? String
self.id = dictionary["userID"] as? String
self.name = dictionary["name"] as? String
self.login = dictionary["username"] as? String
self.email = dictionary["email"] as? String
self.profileImageUrl = dictionary["profileImageUrl"] as? String
self.role = dictionary["role"] as? String
}
}
Message.swift model:
import UIKit
import Firebase
class Message: NSObject {
var fromId: String?
var text: String?
var timestamp: NSNumber?
var toId: String?
var imageUrl: String?
var videoUrl: String?
var imageWidth: NSNumber?
var imageHeight: NSNumber?
init(dictionary: [String: Any]) {
self.fromId = dictionary["fromId"] as? String
self.text = dictionary["text"] as? String
self.toId = dictionary["toId"] as? String
self.timestamp = dictionary["timestamp"] as? NSNumber
self.imageUrl = dictionary["imageUrl"] as? String
self.videoUrl = dictionary["videoUrl"] as? String
self.imageWidth = dictionary["imageWidth"] as? NSNumber
self.imageHeight = dictionary["imageHeight"] as? NSNumber
}
func chatPartnerId() -> String? {
return fromId == Auth.auth().currentUser?.uid ? toId : fromId
}
}
Well currently you have From / To.
So To is going to be a room rather than a person.
Users will need to be able to join a room (or rooms) in order to see the messages that are sent to that room.
So your need a Rooms node.
If you have a messages node then you can just sort by To (room) instead of To (user) to get all the messages sent in that chat room. From will always be the User that wrote the message
How i can display users with unique role on TableView. For example i want to display users only with role "user", or only with role "guest".
my User model:
import Foundation
import Firebase
class User: NSObject {
var id: String?
var name: String?
var login: String?
var email: String?
var profileImageUrl: String?
var role: String?
var isOnline: String?
init(dictionary: [String: AnyObject]) {
self.isOnline = dictionary["isOnline"] as? String
self.id = dictionary["userID"] as? String
self.name = dictionary["name"] as? String
self.login = dictionary["username"] as? String
self.email = dictionary["email"] as? String
self.profileImageUrl = dictionary["profileImageUrl"] as? String
self.role = dictionary["role"] as? String
}
}
My Firebase user model:
You could simple filter the array of users by the role.
self.guests = self.users.filter({$0.role == "guest"})
Then display the list of guests just like any other UITableView.
I hope you could help me:
I try to fetch userdata from a firebase database into a user class and call "setValuesForKeys". I do understand that my class properties have to be exactly the same as in the firebase dictionary, but I've got the error "this class is not key value coding-compliant for the key city."
func fetchUsers(){
Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in
if let usersDictionary = snapshot.value as? [String: String] {
let users = Userdata()
users.setValuesForKeys(usersDictionary)
}
}, withCancel: nil)
}
And my user class is
class Userdata: NSObject {
var email: String?
var password: String?
var firstname: String?
var lastname: String?
var street: String?
var streetno: String?
var zipcode: String?
var city: String?
var phone: String? }
The snapshot from firebase looks like
Snap (ndLBXXX75Oe9Y1PXrqfISL8A4v82) {
city = Washington;
email = "1#a.com";
firstname = Andre;
lastname = Doe;
password = xxxxxx;
phone = "";
street = "Mainstreet";
streetno = 1;
zipcode = 11111;
}
And the dictionary from the database looks like
["city": Washington, "firstname": Andre, "lastname": Doe, "email": 1#a.com, "password": xxxxxx, "streetno": 1, "phone": , "street": Mainstreet, "zipcode": 11111]
I have a solution so far by using:
users.city = dictionary["city"]
My question / problem: I do want to understand the problem behind the error message "this class is not key value coding-compliant for the key city." because the key at the class and in the firebase snapshot looks like the same.
Working solution: I had to extend my user class. Now, the whole user class looks like:
Here is the code :
import Foundation
class UserData: NSObject {
var id: String?
var email: String?
var password: String?
var salutation: String?
var degree: String?
var firstname: String?
var lastname: String?
var street: String?
var streetno: String?
var zipcode: String?
var city: String?
var phone: String?
var profileImage: String?
init(dictionary: [String: Any]) {
self.city = dictionary["city"] as? String
self.id = dictionary["id"] as? String
self.email = dictionary["email"] as? String
self.salutation = dictionary["salutation"] as? String
self.degree = dictionary["degree"] as? String
self.firstname = dictionary["firstname"] as? String
self.lastname = dictionary["lastname"] as? String
self.password = dictionary["password"] as? String
self.phone = dictionary["phone"] as? String
self.street = dictionary["street"] as? String
self.streetno = dictionary["streetno"] as? String
self.zipcode = dictionary["zipcode"] as? String
self.profileImage = dictionary["profileImage"] as? String
}
}