How to structure NoSQL messages to get unreads by

2020-02-13 05:38发布

Say I have NoSQL structure as follows:

messages  
  chat_id (known)  
    message_id (generated automatically)  
      {author, timestamp, content}

I also have users/ branch where I can see last logins of both users involved.
I want to get the number of unread messages for a given user by 1 query.

How would you implement such a task?

2条回答
冷血范
2楼-- · 2020-02-13 06:00

There are two parts to this problem:

  1. Counting the number of messages
  2. Tracking what a user has read

Counting the number of messages

Assuming you are using the Firebase Realtime Database or Cloud Firestore, there are two typical approaches to counting:

  1. Load the unread messages and count them client-side.
  2. Keep a counter of the messages in the database, and update that every time you read/write a message.

Counting the messages client-side is easiest to implement, so typically what inexperienced developers start with. When the number of messages is low, that works fine. But as the number of messages grows, you'll be download more and more data.

At that point you'll switch to keeping a counter in the database and updating that on every write/delete operation. This duplicates data, so is typically something that developers with a background in relational databases struggle with. But it is the most common approach.

You can update the counter client-side, or use a server-side approach such as this example of maintaining counters in Cloud Functions.

Tracking what the user has read

To know how many unread messages a user has, you need to know what the user has already read. Here again, there are two common approaches:

  1. Track each individual message the user has read.
  2. Track the ID of the most recent message the user has read.

Tracking the individual messages sounds most correct, so I see this being done a lot. I also see developers struggling with it, since it involves a lot of book keeping. It's definitely possible, but I'd recommend starting with a simpler approach...

Chat apps deal with (chronological) sequences of messages. If you know the ID of the latest message that the user has seen, you could assume that the user has also seen all messages that are older than that.

Say that I track the timestamp of the last message you read, and it's 1535725374298. I can now query the chat to only retrieve messages newer than that:

firebase.database()
  .ref("chat")
  .child(chatId)
  .orderByChild("timestamp")
  .startAt(1535725374298)
查看更多
虎瘦雄心在
3楼-- · 2020-02-13 06:02

Provided you are using Firebase Authentication's user id's, uid's, which provides a consistent uid for a user across devices, setting message id's to the /users/$uid document is the way to go.

Now, all you have to do is listen to the /users/$user document with the .onSnapshot(). Once the client takes action to read a message in a snapshot, simply delete that message id from the users/$uid node.

How you store the message id's in users/$uid (the userDocument) is kind of up to you - could be an array or could be a nested object, it might even be possible to store message id's individually as type reference, provided there is a way to identify type == reference client-side (so you can iterate the doc fields looking for unread messages in your realtime snapshot).

The advantage to this is that you simplify your code/system. Let Firebase send you updates (new unread messages) as they happen.

查看更多
登录 后发表回答