10

I'm building real time chat, very similar with skype one. I use firebase as backend and angularfire on client side. Basically, all things are look clear, but I've stuck with one thing - showing of unread messages count.

App uses very simple Firebase design: 2 or more users can chat in a "room" - root collection with unique name. Chat message except of text can contain "metadata" - sender id, timestamp, etc.

Simply, I need an emulation of this pseudo-code:

room.messages.where({ unread: true }).count()

For now, according to this, (Can I count the children at a location without retrieving the actual child data?) and this I'm trying to manage unread messages count per room by transactions and reset count when viewed. But it is very tricky part, and I'm curious, do we have any recommended approach here, which can reduce amount of job?

Community
  • 1
  • 1
user2620800
  • 161
  • 1
  • 2
  • 7

2 Answers2

2

It seems like you've pretty much answered it. There is no WHERE clause in Firebase, and the solution is to use snap.numChildren() as the FAQ states, or to use a counter, as the second link states.

If you are going to fetch the chat messages anyway, or it's a one-on-one chat where the total payload would be a hundred kilobytes or less (twenty or so 10kb messages), then just use numChildren. If the message payload is going to be rather large, then set up the counters.

So you would maintain a counter of:

  • how many messages your user has read
  • how many messages exist
  • the difference is the number of unread messages

Since your "messages exist" counter would be updated by multiple users concurrently, you'd use a transaction to accomplish this without conflicts:

new Firebase(URL_TO_COUNTER).transaction(function(currValue) {
    return (currValue||0)+1;
}, function(err, success, snap) {
    if( err ) { throw err; }
    console.log('counter updated to '+snap.val());
});
Kato
  • 40,352
  • 6
  • 119
  • 149
  • Hey @Kato , Any suggestions on how i can track how many messages a user has read? I am assuming i store these 3 counters in the room itself as total messages and number of messages read by each user. Although i dont see how i can detect if a a user read a message. – Nikhil Jan 19 '16 at 23:11
  • 26
    I'd recommend just keeping a timestamp of the last time the user has visited the room, and [query](https://www.firebase.com/docs/web/guide/retrieving-data.html#section-queries) for messages that have been received since then. This should scale well into the thousands. If your chat rooms have millions of messages (hint: they don't) you could get a bit more mileage by using the gmail approach and only grabbing up to 1k messages and saying something along the lines of "1000 or more unread messages" – Kato Jan 20 '16 at 05:13
  • Yes this makes sense, I wouldnt have to maintain counters this way and with the firebase presence system it is quite fast. Thanks @Kato – Nikhil Jan 20 '16 at 16:45
  • 1
    you would have to query for when they left the room and not since they visited, correct? Otherwise you would count as unread those messages they read while in the room. – MonkeyBonkey May 15 '18 at 14:14
  • The only issue with that approach is that it has to be done on a "per chat" basis. In theory this query has to be run for many chats (check your WhatsApp/Telegram app, you probably have well over 80-100 chats), so this would have to run in the database for 80-100 chats, right? Is there any more efficient approach? – Benjamin Heinke May 04 '21 at 02:29
  • Yes, if you're building a social media app where a user receives a feed, then use a per-user feed so they don't have to query across multiple discussions. Btw, those are closer to "threads" than chat rooms. – Kato May 10 '21 at 21:21
0

Don't reinvent the wheel :) Full working solution with code sample including unread messages by the Firebase team at https://firechat.firebaseapp.com

giorgio79
  • 3,787
  • 9
  • 53
  • 85