Firebase realtime database structure in chat app
Solution 1
If you do a structure like similar to this:
-chats
- chatUID
- members
- userUID
- lastMessageSent:messageUID
- ... more properties
-chatMessages
- chatUID
- messageUID
- sentBy: userUID
- messageDate:""
- messageTime:""
- message:""
-userChats
- userUID
- chatUID
you can attach a listener to /userChats/userUID, which will display active chats, and a listener to /chatMessages/chatUID, which will get all chat messages for a specific chat conversation.
This way is a lot easier to setup firebase security rules, and users will only receive chat messages which they are apart of.
Solution 2
Thanks to @Linxy for a brilliant answer
I have created a firebase database regarding @Linxy answer
Here is the complete JSON export
{
"Chats" : {
"-Lsfsd234xda" : {
"lastMessageSent" : "-LrDEBo1-Message",
"members" : [ "-LrDEBoLokW-5mhaT3ys", "-LrDEBoLokW-5mhaT3yz" ],
"more_properties" : "goes here"
}
},
"Users" : {
"-LrDEBoLokW-5mhaT3ys" : {
"id" : "-LrDEBoLokW-5mhaT3ys",
"userDisplayName" : "Qadir Hussain",
"userEmail" : "[email protected]",
"userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7XXXXXXXXX"
},
"-LrDEBoLokW-5mhaT3yz" : {
"id" : "-LrDEBoLokW-5mhaT3yz",
"userDisplayName" : "Ishaq Bhojani",
"userEmail" : "[email protected]",
"userPhotoUrl" : "https://lh3.googleusercontent.com/a-/AAuE7mB3KTbXXXXXXXX"
}
},
"chatMessages" : {
"-Lsfsd234xda" : {
"-LrDEBo-MessageUID" : {
"message" : "Hi there!",
"messageDate" : "10/10/2019",
"messageTime" : "10:16pm",
"sentBy" : "-LrDEBoLokW-5mhaT3ys"
},
"-LrDEBo1-MessageUID" : {
"message" : "Hello",
"messageDate" : "10/10/2019",
"messageTime" : "10:17pm",
"sentBy" : "-LrDEBoLokW-5mhaT3yz"
}
}
},
"userChats" : {
"-LrDEBoLokW-5mhaT3ys" : {
"0" : "-Lsfsd234xda",
"1" : "-Lsfsd234xda1",
"chatUID" : "-Lsfsd234xda"
}
}
}
Solution 3
I know it's late to answer but for future readers although Linxy's answer is neater, I would like to point out a more efficient one having been tried both structures:
ChatMessages
smallerUID_biggerUID
messageUID
sentBy : userUID
messageDate : ""
message : ""
.
.
.
.
UserChats
userUID
pairUID
lastMessage : ""
.
.
.
.
In this way, instead of first finding out the chatId then finding out which user is associated with that chatId, we can directly search which users should appear in our active chat tab and get thouse users' information (username, profilePicture). The reason for that is we can always calculate the chatId if we know the user's id we would like to message with. So for the message tab, we calculate the chatId (smallerUID_biggerUID) in client side and search for the messages in referencing it.
Solution 4
In order to structure your database, please read this post: Structuring your Firebase Data correctly for a Complex App. You'll find here for sure the answer to your question.
As a conclusion, try to flatten(denormalize) your database as much as possible.
Hope it helps.
![Agustin](https://i.stack.imgur.com/DSn6k.png?s=256&g=1)
Agustin
Updated on February 04, 2022Comments
-
Agustin over 2 years
sorry for my bad English level, I'm from Argentina.
I have the following messages data structure in Firebase:
"messages" "-KezmqXSdKCNFFA432Uc___-KfCEwklG_y3naRDIUiY" "messageDate": "20170620" "messageTime": "18:44" "message": "Hi" "-KezFDSAADFASFFS3221___-KASDF32324SDFASD1FS" "messageDate": "20170620" "messageTime": "22:23" "message": "How are you?"
Where -KezmqXSdKCNFFA432Uc, -KfCEwklG_y3naRDIUiY, -KezFDSAADFASFFS3221 and -KASDF32324SDFASD1FS are users.
My problem is that I created a childEventListener in "messages" node to receive new users messages but I am receiving all the new messages of all the users (I'm logged in one user per app) because my childListener is in "messages" node.
Is it correct that if I have 1000 users when adding a message, a new message reaches the 1000 users? (Assuming that within the app, you can check to which user that message belongs).
Thanks!
-
Agustin about 7 yearsI understand but then I should create channels for each conversation between two users and let these users listen to that channel by a childlistener? In this case, should you create dynamic channels and dynamic childevents?
-
Oussema Aroua about 7 yearsthe channel will be created once one of them send a message to the other and add it to both users channel list, you can use firebase functions to add trigers on the database to send the push notification or add a listener on the channels node and test if the user own that channel, or add event listener on the specified nodes
-
Agustin about 7 yearsIn that case, a user should be connected to as many childlisteners as they have conversations. This is the right way?
-
Oussema Aroua about 7 yearsunfortunately yes, that why you need to use firebase functions so you don't need local notification and get push
-
Agustin about 7 yearsSo I read about firebase functions, I should create a new channel in firebase from user "A" and then create a function to indicate to user "B" that he has received a message and that he must connect a listener to the channel. But that function, should be created from android?
-
Oussema Aroua about 7 yearsyou will write a trigger on the database, when a channel changes send a notification to the other user at the channel check this [link] (firebase.google.com/docs/functions/database-events)
-
Agustin about 7 yearsI see. Anyway I would need to implement functions and triggers from firebase, right?
-
Adi over 5 yearsThis is the most inefficient solution. You are making all users to get every data in the system. Your app will never scale.
-
Eduard over 5 yearsWhile usable, that's very dumb. If I have 5000 conversations, every time you log in or the user gets updated, you will load all 5000 conversation IDs :)
-
kernelman about 5 years@Linxy userA and userB are in a chat room, and both have added a listener to
/chatMessages/chatUID
. Now if userA pushes a new message inchatUid
, both users A&B will receive this new message through their listeners ? Isnt this a waste of Bandwidth for userA, since he himself pushed it. Is it possible to have a Db structure so that userA will only listen to messages from userB ? -
Tarvo Mäesepp almost 5 yearsHow would you count unred messages in this case? This question is old and uses realtime database instead of firestore which I use but I have the same thing pretty much with collections. I also asked question
-
TakeMeHomeCountryRoads about 4 yearsCan you explain your reasoning a little more, I am confused about how you would calculate the uid clientside. Wouldn't you have to go through all of the users and mix and match?
-
Denton about 4 yearsNot really sure if I got the unclear point so let me explain with an example. Say we have an activity displaying active chat users (users the client has at least 1 message with). To display this, we get the data under UserChats/userUID(the client's id). Then when the client clicks one of the users, we need to show the messages between the client and the clicked user. Every messaging pair is uniquely identified as "smallerUID_biggerUID". We already got the uid we would like to see the messages the client has with and we know our own id. So we can calculate this pair's chatId and get their mssgs
-
TakeMeHomeCountryRoads almost 4 yearsThe smaller and larger UID makes sense to me, but using this system, wouldn't you still have to query all of the other users UIDs in order to calculate all of the other chat node ids
-
Denton almost 4 yearsYou can calculate the chatIds of the people we chat with before by attaching a listener to UserChats/userUID. But i think i got what you are asking now. To get all the userUIDs, You can simply get all the userUIDs from Users with any type of query you like and display them. Only when you click one of the users, you will need to calculate the chatid and attach a listener to chatMessages. So what im trying to say is you dont need to get or calculate all the chatIds. The recyclerview elements should contain only the pairInfo (pairUsername, pairUID etc), not the chatId.
-
PeakGen over 3 yearsCan you please share the code you used to setup this structure?
-
Nischal Kumar over 3 yearsAlso, this will require a listener for each charUid. Maintaining all these listeners could be memory intensive where a user generally has 1k chat rooms.
-
Morris S over 2 yearshow do you query for the receiver of the message without knowing the chatUID only the userUID of the sender?