0

I'm working on a chat client using the firebase realtime database as the database. The way that it currently works is that it saves a chat log between two people in a chat collection with each entry in the following format <uid>-<uid>. This works great as it just looks your uid and the uid of the person you want to chat with and then sorts them, so it's always a consistent format and then it looks if that entry exists on the chat collection and if so, it just adds to that entry. Otherwise it creates a new one.

enter image description here

This works awesome. I'm trying to think ahead though if we want to be able to have multiple people talk together like in slack. I could just add 3 or even 4 people's uid as the key but eventually it's going to be insanely long. The limitation of a firebase key is 768 Bytes. Apparently that's somewhere between 500 and 700 characters. I doubt we will have the key get that long, but if we can figure out a solution that is more scalable now and won't require us to fix our data later, i'd rather do that. I was thinking that each chat entry could have a participants array with the uid's of all the users in that chat. Then if you want to chat with someone, we would need to query all chat entries and check the arrays in each of them for the current user uid and the uid of the person(s) they want to chat with. That doesn't seem very efficient though.

Any thoughts on which implementation is better / more scalable / performant? Or perhaps a suggestion for another implementation?

zeckdude
  • 15,877
  • 43
  • 139
  • 187
  • If you want to optimize for performance and flexibility, you have to define the queries you want to perform ahead of time. The way nosql databases work is not as flexible as SQL, and if you don't know what your queries are, you don't know how to structure your data. Changes in queries may require structural changes or duplication in your data. – Doug Stevenson Aug 30 '18 at 16:43
  • I’m sorry @DougStevenson, but I’m not following you. Can you provide a code sample or relevant link? – zeckdude Aug 30 '18 at 16:54
  • I'm speaking in a general sense about data modeling, not providing an answer. That's why it's a comment and not an answer. – Doug Stevenson Aug 30 '18 at 17:16

1 Answers1

2

How about simply using the hash of the resulting concatenation of UIDs?

Alternatively:

  1. Come up with your own unique room key, e.g. using a push ID.
  2. create a new top-level node with chatroom-keys and store the concatenated UID as the value there:

    chatroom-keys push-id1: uid1-uid2-uid3 push-id2: uid1-uid2-uid3-uid4-uid5-uid6 push-id3: uid3-uid4-uid5-uid6-uid7-uid8-uid8-uid10

In this structure you can look up the room key for a set of participants by:

firebase.database().ref("chatroom-keys").orderByValue().equalTo("uid1-uid2-uid3")
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks for the reply Puf! The hash of the concatenation of UID's I am realizing that once the chat has begun with the specified users, then if I want to add another user to the chat, I would need to start a new chat with the previous users as well as the new user. This doesn't seem ideal. But it seems that your alternative solution will solve that problem, right? Cause I could just add/remove a uid from the value for a specific chatroom-key, right? – zeckdude Aug 30 '18 at 15:06
  • 1
    Yeah, that problem would be the same for both. It's actually quite common for chat tools to consider adding a new person to be a new chat room (and so to lose history). I wrote an answer about that a while ago here: https://stackoverflow.com/questions/51580191/allow-users-to-send-messages-to-multiple-users-simultaneously-in-a-messaging-app. Typically I'd use "named rooms" for the other scenario you describe and keep a `userRooms` list, where you associate each `UID` with their rooms. – Frank van Puffelen Aug 30 '18 at 19:09
  • It seems to me that your idea solves that, as we can remove a specific uid & then the user no longer has access. If we add a uid, then the new user gets access to the messages for the existing room and can see previous messages. Am I missing something? Another idea that I think would work is that each chat entry in the `chat` collection is a chat room. Each chat room has a `participants` string property with the UID's and messages object property where the messages get pushed. Then I can remove/add participants from/to the `participants` property as needed. Do you see any problem with that? – zeckdude Aug 31 '18 at 00:21
  • You'll typically want both: `/participantRooms` and `/roomParticipants`. In `participantRooms` each key is a UID and under that you have their room IDs. In `roomParticipants` each key is a room ID, and under that you keep the participant's UIDs. You can then check in security rules that users only can read the rooms they participate in. Keeping all in top-level collections allows these security rules, and keep loading the lists as lightweight as possible. – Frank van Puffelen Aug 31 '18 at 02:24
  • Why would I need data to at the top-level to allow security rules like you mentioned? Do you know of any supporting documentation that explains that in more detail? – zeckdude Sep 05 '18 at 05:17