moxmlb
moxmlb

Reputation: 1330

Swift Firebase get Data to Class Object

I want to get the following structure (screenshot of Firebase Database):

enter image description here

In chats I have the id of the chat. There are the users with the child userid and the values of id and name. At first I look for the chats which a user have and want to get then the details of the chatId (users with their id and name)

I have the following class in Swift:

class Chat {
var chatId: String!
var userIds: [String]!
var userNames: [String]!
}

I have the following code to get the details, but I get not the userIds or userNames from the chatId:

func getChatsFromFirebase() {
    self.ref = Database.database().reference()
    self.ref?.child("users").child(userdefaults.getUserId()).child("chats").observe(.childAdded, with: { (snapshot) in
        let chat = Chat()
        chat.chatId = snapshot.key
        chat.userIds = []
        chat.userNames = []

        //print(chat.chatId)

        for i in 0..<self.chats.count {
            let usersRef = self.ref.child("chats").child(self.chats[i].chatId).child("users").observeSingleEvent(of: .value, with: { (snapshot) in
                let value = snapshot.value as? NSDictionary

                for userid in value!.allKeys as! [String] {
                    let usersdetailsRef = self.ref.child("chats").child(self.chats[i].chatId).child("users").child(userid).queryOrdered(byChild: "name").observeSingleEvent(of: .value, with: { (snapshot) in

                        let value = snapshot.value as? NSDictionary
                        //print(value)
                        let id = value?["id"] as? String ?? ""
                        let name = value?["name"] as? String ?? ""
                        //print( id + ": " + name)
                        chat.userIds.append(id)
                        chat.userNames.append(name)
                    })
                }
            })
        }
        self.chats.append(chat)
        self.tableView.reloadData()
    })
}

I am very new to the Firebase topic. Can someone help me here? Thanks.

Upvotes: 1

Views: 950

Answers (1)

Aakash Dave
Aakash Dave

Reputation: 896

Well You need to change your datamodel first. You dont need to store id value in , 12345 in this case. you can already fetch the key. Also, in /users/chats, you just can just save the chat id as either chat1 : IBDrbfku887BLIY or IBDrbfku887BLIY : true. You can always fetch them through value or the key respectively.

And in your chat document, you just need to reference the user id, i.e just get them and store them as user1 and user2. You can add more users if your usecase requires more.

Reconfigure your Data Model as follows.

enter image description here

Now You need 2 Objects Users and Chats as follows :

Users.swift

class User : NSObject {

        private var _name: String!
        private var _username: String!
        private var _userid: String!
        private var _userRef: DatabaseReference!

        var name: String! {
            get {
                return _name
            } set {
                _name = newValue
            }
        }


        var username : String! {
            get {
                return _username
            } set {
                _username = newValue
            }
        }


        var userid: String! {
            get {
                return _userid
            } set {
                _userid = newValue
            }
        }

        var userRef: DatabaseReference! {
            get {
                return _userRef
            } set {
                _userRef = newValue
            }
        }

        init(userid: String, userData: Dictionary<String, Any>){

            self._userid = userid

            _userRef = Database.database().reference().child(_userid)

            if let username = userData["username"] as? String {
                self._username = username
            }

            if let name = userData["name"] as? String {
                self._name = name
            }

        }

    }

Chats.swift

class Chat : NSObject {

        private var _chatid: String!
        private var _user1: String!
        private var _user2: String!
        private var _chatRef: DatabaseReference!

        var user1: String! {
            get {
                return _user1
            } set {
                _user1 = newValue
            }
        }


        var user2 : String! {
            get {
                return _user2
            } set {
                _user2 = newValue
            }
        }


        var chatid: String! {
            get {
                return _chatid
            } set {
                _chatid = newValue
            }
        }

        var chatRef: DatabaseReference! {
            get {
                return _chatRef
            } set {
                _chatRef = newValue
            }
        }

        init(chatid: String, chatData: Dictionary<String, Any>){

            self._chatid = chatid

            _chatRef = Database.database().reference().child(_chatid)

            if let user = chatData["users"] as? Dictionary<String, Any> {
                if let user1 = user["user1"] as? String {
                    self._user1 = user1
                }
                if let user2 = user["user2"] as? String {
                    self._user2 = user2
                }
            }

        }

    }

The major issue/or an overlooked issue here is the type of the data. In the /users, you id 12345 will be of type String. But when you fetch the same from /chats, it returns as Int. This downloads the value but never converts it. Always take care while seeding/testing your data.

To fetch the user's credentials just reference that through another query. This is what you can do :

var allUsers = [User]()
    var allChats = [Chat]()

    func viewDidLoad() {
        super.viewDidLoad()
        fetchAllChats()
    }

    func getUser(from userId: String, completion: @escaping (User) -> Void) {

        Database.database().reference().child("users").child(userId).observeSingleEvent(of: .value, with: { snapshot in
            if let datasnap = snapshot.value as? Dictionary<String, Any> {
                let user = User(userid: userId, userData: datasnap)
                completion(user)
            }
        })
    }

    func fetchAllChats() {
        Database.database().reference().child("chats").observeSingleEvent(of: .value, with: { snapshot in
           allChat.removeAll()
            if let snapshot = snapshot.value as? Dictionary<String, Any> {
                for snap in snapshot {
                    if let chatd = snap.value as? Dictionary<String, Any> {
                        let chat = Chat(chatid: snap.key, chatData: chatd)
                        self.allChats.append(chat)
                    }
                }
            }
            // collectionview.reloadData() <--------- only if required.
        })
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let chatData = allChats[indexPath.row]
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CellId, for: indexPath) as! Cell
        getUser(from: chatData.user1) { user in
            cell.label.text = user.usernme
        }
        return cell
    }

Upvotes: 1

Related Questions