KevinB
KevinB

Reputation: 2484

Count unseen messages with Firebase in Swift

I'm trying to code a chat app.

I would like to count the number of messages, which are not viewed (unseen).

My database looks like this:

user-messages
 |
 |_messages
    |
    |_UserID1
    |   |
    |   |_UserID2
    |     |
    |     |_ MessageID1
    |     |_ MessageID2
    |     |_ MessageID3
    |     |_ etc...
    |     
    |_UserID2
    |   |
    |   |_UserID1
    |     |
    |     |_ MessageID1
    |     |_ MessageID2
    |     |_ MessageID3
    |     |_ etc...

And for the Messages object:

messages
 |
 |_messageID1
 |  |
 |  |_ notViewed: false / true
 |  |_ text: "Message text"
 |  |_ timestamp: 1522230692
 |  |_ etc...
 |  
 |_messageID2
 |  |
 |  |_ notViewed: false / true
 |  |_ text: "Message text"
 |  |_ timestamp: 1522230692
 |  |_ etc...

I arrived to get all the message ID which are linked to a specific user:

var REF_MESSAGE = Database.database().reference().child("messages")
var REF_USER_MESSAGE = Database.database().reference().child("user-messages").child("messages")


func fetchUnviewedMessages(withId id: String, completion: @escaping (Int) -> Void ) {

      REF_USER_MESSAGE.child(id).observe(.childAdded) { (snapshot) in

         let userId = snapshot.key as String

         self.REF_USER_MESSAGE.child(id).child(userId).observe(.childAdded, with: { (snapshot) in
            let messageId = snapshot.key

                // This part is where I have a problem
                self.fetchMessageNotViewed(messageId, completion: { (nbMessageNotRead)  in
                   completion(nbMessageNotRead)
                })
             })
          }
    }

But I don't know what I need to do with that list, to observe the number of unseen messages ...

I tried that, but without success:

func fetchMessageNotViewed(_ messageId: String, completion: @escaping (Int) -> Void) {
      guard let currentUid = Api.User.CURRENT_USER?.uid else {
         return
      }

      REF_MESSAGE.child(messageId).queryOrdered(byChild: "notViewed").queryEqual(toValue: true).observe(.value, with: { (snapshot) in

         let count = Int(snapshot.childrenCount)
         print(count)
      }, withCancel: nil)
}

Upvotes: 1

Views: 3674

Answers (2)

Jay
Jay

Reputation: 35658

We can leverage a compound value to handle this fairly easily.

Make a simple change to the Firebase structure messages node:

messages
 |
 |_messageID1
 |  |
 |  |_ notViewed: false / true
 |  |_ text: "Message text"
 |  |_ timestamp: 1522230692
 |  |_ forUid_status: "UserId1_unread"   //<- Compound value
 |  |_ etc...
 |  
 |_messageID2
 |  |
 |  |_ notViewed: false / true
 |  |_ text: "Message text"
 |  |_ timestamp: 1522230692
 |  |_ forUid_status: "UserId1_read"   //<- Compound value
 |  |_ etc...

then a simple query will reveal a count of UserId1 unread messages

let messagesRef = self.ref.child("messages")
let uid = "UserId1"
let status = "unread"
let queryString = uid + "_" + status //results in a string UserId1_unread

let ref = messagesRef.queryOrdered(byChild: "forUid_status").queryEqual(toValue: queryString)
ref.observe(.value, with: { snapshot in
    if snapshot.exists() {
        let count = snapshot.childrenCount
        print("unread messages: \(count)")
    } else {
        print("no unread messages")
    }
})

running this code against the above Firebase results in

unread messages: 1

This may also help with the loading of unread messages as not only can you get their count but adding the observer to that node will also notify the app any time a new unread message is added for UserId1

Upvotes: 3

Abhirajsinh Thakore
Abhirajsinh Thakore

Reputation: 1822

As on request by @KevinB

You can use my logic to show the counter in message popup

Step:-1 WebService call/Firebase Fetch:

Fetch the array of message data in app.In my case, i was having an array of messages in response and store the count of it an userDefault. For E.g:-

UserDefaults.standard.set(arrMessageData.count, forKey: "messageCount")

Step:-2 Set Counter-Zero when message is read Or Appending the old value with new value

Case:1 Reading the Message

In my case i was having a separate popup for reading the message. when that pop-up was opened i was forcefully making the value of my userDefault value to 0

UserDefaults.standard.set(0, forKey: "messageCount")

Case:1 If message is un-read

In that case if pop-up is not opened so in that case there will be some value in userDefault. In this case First fetch the current count in userDefault and then make the WSCall and get the new count and Add both and then save in same key.

Note:- The idea of storing the counter in userDefault is used because it can be accessed anywhere in app and can directly be shown in any label or button.

Upvotes: 0

Related Questions