Loading conversation messages in chat app with Firestore - firebase

When building a chat app with React Native and Redux, with Firestore for backend, what is the best way to load messages for a particular conversation?
I display 8 chat entries in the beginning, and when I click at one I will see the chat screen with 20 latest messages. Is it a good idea to implement real time listeners to each chat's (not all chats, just those that are displayed, because pagination is used) 20 latest messages from each one's messages collection and have them ready beforehand?
Or is it a better idea to load the messages when a particular chat's messages screen is being opened.
I understand that as user experience the first option is better because there is no latency in showing the first 20 messages for a chat, but doesn't it consume a lot of data that might never be necessary, because out of the 8 chats, the user might interact with only 2 or 3.
Is there any better way besides these two?
Thanks in advance!

If is a good idea or not, it's up to you to decide according to what kind of chat app you want to create. It's always a trade between the latency that you were talking about and the amount of data that you get and that might be or might not be seen by the user. Furthermore, if you say you have 8 chat rooms with 20 messages, it means that by default, when the user opens your chat app, Firestore will charge you with 8*20=160 read operations, even if the user enters a chat room or not and I think is not such a good idea. If you have a few users, there won't be a problem but if your app grows, you might think again about this. In Firestore, everything is about the number of reads and writes according to their pricing plan.

In my opinion, you should think of upgrading your UX by giving the app offline capabilities instead of loading unnecessary data all at one. You should fetch data for a concerned chat and make your app memorize the latest 10-20 messages and you can always sync your data. You might want to consider Realm or SQLite.
Also for better UX for the chats screen where the chats will be shown, you should consider making your chat-list node to accomodate last message and timestamp in each chat so that you wont have to nest the query for each chat item for just one screen rendering.

Related

flutter firebase with streambuilder: Is server fee going to increase exponentially?

I'm beginner in flutter-fire app [: And here i've got a simple issue but not easy to figure out.
When we use Streambuilder in the app, we can usually see awesome synchronization between UI and DB on time. I'm really feeling joyful when using Streambuilder. It seemed like only beautiful things would happen with Streambuilder.
Meanwhile, a suspicious question popped out. When we enter print('hello world!'); in the Streambuilder, we can see that RUN console is printing out the phrase every milliseconds, otherwise would be just printed once. It means that RAM usage is extremely increased. When it comes to DB synchronization, we can easily guess that the use of Streambuilder leads to huge usage of client-server communication fee, which in my case is Firebase fee.
So, here is my question.
Can i feel free to use Streambuilder when the stream is connected to DB(in my case, firebase)?
I'm worrying about communication fee between UI and firebase, because streambuilder seems like literally using huge amount of energy every milliseconds(IMO additionally, server fee) unlike normal builders. Especially when the length of collection is so long that reading the collection once may cost a lot of energy, the fee would increase a lot more on and on, because the streambuilder have to check thousands of firebase documents only to figure out a single line of condition.
I guess many backend-connected flutter methods use the Streambuilder, so someone could clearly figure it out how much we're gonna pay for Google when we use Streambuilder. I know it's quite ambiguous question, but hope you understand. [:
Content coming from the Firebase database, whether FutureBuilder or StreamBuilder, pays only for the query value that has been processed once, and after that, in case the same response value is the same for the same query, it does not pay for that cost and displays the stored list stored in the cache on the client screen again. .
And check that it's not being called on something like setState. if so, of course StreamBuilder is called again.

How to know if a message is seen or not

We are displaying list of messages on user message feed. Messages are stored in a feed collection, where its organized by users. We want want track if user has seen the message or not
feed/{user_id}/
{message_id1: {seen:0,score:0.2}}
{message_id2: {seen:0,score:0.2}}
{message_id3: {seen:1,score:0.2}}
At present we are thinking to update "seen" boolean for a given message if user has seen it. Are there more efficient ways to do this in firebase (e.g. firebase native analytics). Not sure if doing so many writes back efficient
There are two common ways to track what messages a user has seen:
Keep a flag for each message that the user has seen.
Keep the timestamp/key of the most recent message that the user has seen.
The letter is a lot easier to implement, but relies in the fact users typically read message in order: scrolling from their oldest unread message to the newest message. If that is not the case for you, there's not really a better option than tracking the status for each message (and in a multi-user chat room, for each user too).
Also see:
How to structure NoSQL messages to get unreads by 1 query? (long explanation with examples of the same use-case, but then for Firebase's Realtime Database)

does accessing the firebase firestore database dashboard will be considered as read operation?

I am now in developing phase for the project. currently the project only using one Android app as the frontend. the query from Android using limit and pagination. but the total number of documents read is way above the expected number.
I am trying to figure this out, why the number of read documents is so big even though the user is only one (me). I am scared the project will not be feasible if the number of read is so big. thats why i need to figure out the firestore read behaviour
When I accessed the firestore dashboard, and select a collection like the image below, it will show blue loading indicator and then show all documents available. currently in the event collection I have 52 documents. I access all documents in the event collection like this for several times for debugging purpose.
so whenever i tap that event collection, I assume it will be counted as 52 read operation, so the read operation will not only come from Android device but also from the dashboard ? thats why the number of reads is so big. am I right ?
if thats the case....
say if I have 100000 documents in event collection, then whenever i tap that event collection, will i perform 100000 read operation as well ? is there a way to limit this dashboard read ?
so the read operation will not only come from the Android device but also from the dashboard? That's why the number of reads is so big. am I right?
Yes, you are right.
say if I have 100000 documents in event collection, then whenever I tap that event collection, will I perform 100000 read operation as well?
No, you'll be charged only for the number of documents that belong to the first page. Inside the Console, there is a pagination mechanism especially implemented for that. So you'll be not charged for all the documents that exist in your collection.
Is there a way to limit this dashboard read?
The limitation already exists but be aware that as much as you scroll down, you get more documents which means more read operations charged.
One thing to bear in mind about the Firebase console is that it reflects changes to visible documents in real time, and each one of those changes also costs you a read. So, if you leave the console open while documents are changing, you will accumulate reads over time, even if you aren't actively using the console. This is a common source of unexpected reads.

Count unseen messages in group chat with firestore

I want to track the number of unseen messages for each member of a group chat. I store chat metadata in a chats collection, and messages for each chat in messages/{chatId}.
I have checked other threads that ask about this, but in this scenario there's a group chat so it's more complicated. The threads that I have read suppose that it's a chat between two people.
I have thought about having a new collection seenMsgTimestamps where I store the timestamp of the last message that a certain user has seen for each group chat. In my app, I will listen to changes to messages starting from the the timestamp found in seenMsgTimestamps for that chat, and count how many new messages are there.
Is this a good approach or is there a better way of doing this?
Thanks in advance.
In my opinion you an go ahead with this solution. Why is this solution good?
I have thought about having a new collection seenMsgTimestamps where I store the timestamp of the last message that a certain user has seen for each group chat.
You denormalize data by creating a new collection, which is a quite common practice when it comes to NoSQL databases. In your particulasr case, I think is the best solution.
In my app, I will listen to changes to messages starting from the the timestamp found in seenMsgTimestamps for that chat
That's also good because you are using a query on a limited data set and not on the entire collection, which means less reads, less money to pay but more perfomance.
Regarding the count, I recommend you also read the last part of my answer from this post. So you can also consider using Firebase realtime database for such conters.

'Assigning a player in multiplayer game' firebase example is not very scalable or is it?

In the firebase example (https://gist.github.com/anantn/4323981), to add an user to the game, we attach the transaction method to playerListRef. Now, every time firebase attempts to update data, it will call the callback passed to the transaction method with the list of userid of all players. If my game supports thousands of users to join at a time, every instance this method executes, the entire user list will be downloaded and passed which will be bad.
If this is true, what is the recommended way to assign users then?
This is specifically what Firebase was designed to handle. If your application needs to actually assign player numbers, this example is the way to go. Otherwise, if the players just need to be in the same "game" or "room" without any notion of ordering you could remove the transaction code to speed things up a bit. The snippet as well as the backend have handled the number of concurrent connections you've mentioned—if you're seeing any specific problems with your code or behavior with Firebase that appears to be a bug, please contact us at support#firebase.com and we can dig into it.

Resources