I am currently trying to architecture an in-app chat feature with firebase realtime-db.
It should contain a UI view where the user can see its latest chats with an active connection to show latest updates.
My current data structure looks sth like this.
"users": [
"UID1": {
"name": "Rocky Balboa",
"lastSeenAt": "2023-01-06T00:00Z",
"chatRooms": ["CR1", "CR2"]
}
]
"chatRooms": [
"CR1": {
"participants": [ "UID1", "UID2", ... ],
"lastMessage": {
"id": "M2",
"message": ":)",
"createdBy": "UID2",
"createdAt": "2023-01-06T00:00Z",
}
}
]
"messages": [
"CR1": [
"M1": {
"message": "Adrian, I did it!",
"createdBy": "UID1",
"createdAt": "2023-01-05T00:00Z"
}
"M2": { ... }
]
]
The steps how I would process to do it in-app looks like this:
- Single fetch on
/users/{UID1}/chatRooms
to get participating chat room keys - Multiple
ValueEventListeners
on chatRooms with fetched data from step 1.
chatRooms/{CR1}
,chatRooms/{CR2}
... and merge them into a Kotlin Flow
My concern now is that these multiple ValueEventListeners are inefficient or even costly.
My other option would be to delete the chatRooms
base path and fan-out all recent changes to users chatRooms
property with all required info like message etc.
Something like this
"users": [
"UID1": {
"name": "Rocky Balboa",
"lastSeenAt": "2023-01-06T00:00Z",
"chatRooms": [
"CR1": {
"participants": [ "UID1", "UID2", ... ],
"lastMessage": {
"id": "M2",
"message": ":)",
"createdBy": "UID2",
"createdAt": "2023-01-06T00:00Z",
}
}
]
}
]
"messages": [
"CR1": [
"M1": {
"message": "Adrian, I did it!",
"createdBy": "UID1",
"createdAt": "2023-01-05T00:00Z"
}
"M2": { ... }
]
]
But in this case I would have duplicated the data (which is not that bad per se since nosql) on every users item and have to update them everywhere. This effort also increases when there are more than 2 participants + will be ugly when db sharding is required. But it would make it possible to listen on multiple chat rooms in one event listener.
What would you prefer? Are my fears justified?