I am trying to build a chat application similar to slack chat, I want to understand how they have designed their database that it returns so much information at once when someone loads a chat, which database is good for this problem, I am adding screenshot of the same for reference.
Initially when I started thinking about this I wanted to go ahead with PostgreSQL and always keeping tables normalized to keep it clean but as I went ahead normalization started to feel like a problem.
Users Table
| id | name | |
|---|---|---|
| 1 | John | john@gmail.com |
| 2 | same | sam@gmail.com |
Channels Table
| id | channel_name |
|---|---|
| 1 | Channel name 1 |
| 2 | Channel name 2 |
Participants table
| id | user_id | channel_id |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 2 | 1 |
Chat table
| id | user_id | channel_id | parent_id | message_text | total_replies | timestamp |
|---|---|---|---|---|---|---|
| 1 | 1 | 1 | null | first message | 0 | - |
| 2 | 1 | 2 | 1 | second message | 10 | - |
| 3 | 1 | 3 | null | third message | 0 | - |
Chat table has column name parent_id which tells if it is parent message or child message I don't want to go with recursive child messages so this is fine
Emojis table
| id | user_id | message_id | emoji_uni-code |
|---|---|---|---|
| 1 | 1 | 12 | U123 |
| 2 | 1 | 12 | U234 |
| 3 | 2 | 14 | U456 |
| 4 | 2 | 14 | U7878 |
| 5 | 3 | 14 | U678 |
A person can react with many emojis on the same message
when someone loads I want to fetch last 10 messages inserted into tables with all the emojis which have been reacted with each messages and replies like you can see in the image where it says 1 reply with person's profile picture(this can be more than 1)
Now to fetch this data I have to join all the tables and then fetch the data which could be very heavy job on the back-end side, considering this is going to be very frequent.
What I thought is I would add two more columns in Chat table which are profile_replies and emoji_reactions_count and both will be of bson data types to store data something like this
This for emoji_reactions_count column
This is also with two ways one which is count only way
{
"U123": "123",// count of reactions on an emoji
"U234": "12"
}
When someone reacts i would update the count and insert or delete the row from Emojis table, Here I have a question, too frequent emoji updates on any message could become slow? because i need to update the count in above table everytime someone reacts with a emoji
OR
storing user id along with the count like this , this looks better I can get rid off Emojis table completely
{
"U123": {
"count": 123, // count of reactions on an emoji
"userIds": [1,2,3,4], // list of users ids who all have reacted
},
"U234": {
"count": 12,
"userIds": [1,2,3,4],
},
}
This for profile_replies column
[
{
"name": 'john',
"profile_image": 'image url',
"replied_on": timestamp
},
... with similar other objects
]
Does this look fine solution or is there anything I can do to imporve or should I switch to some noSQL Database like mongodb or cassandra? I have considered about mongodb but this does not also look very good because joins are slow when data exponentially grows but this does not happen in sql comparatively.
