Count unseen messages in group chat with firestore - firebase

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.

Related

Firestore data model for events planning app

I am new to Firestore and building an event planning app but I am unsure what the best way to structure the data is taking into account the speed of queries and Firestore costs based on reads etc. In both options I can think of, I have a users collection and an events collection
Option 1:
In the users collection, each user has an array of eventIds for events they are hosting and also events they are attending. Then I query the events collection for those eventIds of that user so I can list the appropriate events to the user
Option 2:
For each event in the events collection, there is a hostId and an array of attendeeIds. So I would query the events collection for events where the hostID === user.id and where attendeeIds.includes(user.id)
I am trying to figure out which is best from a performance and a costs perspective taking into account there could be thousands of events to iterate through. Is it better to search events collections by an eventId as it will stop iterating when all events are found or is that slow since it will be searching for one eventId at a time? Maybe there is a better way to do this than I haven't mentioned above. Would really appreciate the feedback.
In addition to #Dharmaraj answer, please note that none of the solutions is better than the other in terms of performance. In Firestore, the query performance depends on the number of documents you request (read) and not on the number of documents you are searching. It doesn't really matter if you search 10 documents in a collection of 100 documents or in a collection that contains 100 million documents, the response time will always be the same.
From a billing perspective, yes, the first solution will imply an additional document to read, since you first need to actually read the user document. However, reading the array and getting all the corresponding events will also be very fast.
Please bear in mind, that in the NoSQL world, we are always structuring a database according to the queries that we intend to perform. So if a query returns the documents that you're interested in, and produces the fewest reads, then that's the solution you should go ahead with. Also remember, that you'll always have to pay a number of reads that is equal to the number of documents the query returns.
Regarding security, both solutions can be secured relatively easily. Now it's up to you to decide which one works better for your use case.
I would recommend going with option 2 because it might save you some reads:
You won't have to query the user's document in the first place and then run another query like where(documentId(), "in", [...userEvents]) or fetch each of them individually if you have many.
When trying to write security rules, you can directly check if an event belongs to the user trying to update the event by resource.data.hostId == request.auth.uid.
When using the first option, you'll have to query the user's document in security rules to check if this eventID is present in that events array (that may cost you another read). Checkout the documentation for more information on billing.

What is the best way to get multiple specific data from collections in firestore?

is there any better way to get multiple specific data from collection in firestore?
Let's say have this collection:
--Feeds (collection)
--feedA (doc)
--comments (collection)
--commentA (doc)
users_in_conversation: [abcdefg, hijklmn, ...] //Field contains list of all user in conversation
Then, I'll need to retrieve the user data (name and avatar) from the Users collection, currently, I did 1 query per user, but it will be slow when there are many people in conversation.
What's the best way to retrieve specific users?
Thanks!
Retrieving the additional names is actually a lot faster than most developers expect, as the requests can often be pipelined over a single HTTP/2 connection. But if you're noticing performance problems, edit your question to show the code you use, the data you have, and the performance you're getting.
A common way to reduce the need to load additional documents is by duplicating data. For example, if you store the name and avatar of the user in each comment document, you won't need to look up the user profile every time you read a comment.
If you come from a background in relational databases, this sort of data duplication may be very unexpected. But it's actually quite common in NoSQL databases.
You will of course then have to consider how to deal with updates to the user profile, for which I recommend reading: How to write denormalized data in Firebase While this is for Firebase's other database, the same concepts apply to Firebase. I also in general recommend watching Getting to know Cloud Firestore.
I have tried some solution, but I think this solution is the best for the case:
When a user posts a comment, write a field of array named discussions in the user document containing the feed/post id.
When user load on a feed/post, get all user data which have its id in the user discussions (using array-contains)
it’s efficient and costs fewer transaction processes.

Modeling one to one chat on firebase

I'm building a one to one messaging feature the intent behind is the following:
There is a unique project and people (two or more) can chat about the project so we can think a project is a room, I've been looking to different modeling structures the most common is something like the following:
Chats
- projectId (room)
- messages
message
userId
name
profilePicture
posted (timestamp)
But I've been thinking in a flat structure something like
Messages
ProjectId
Message
userId
name
profilePicture
posted
The chat feature is going to have a huge impact on the web app I'm building, being said that is quite important to make the right desition (I'm sure there is no always a right or wrong but consider the purpose of the chat)
Just some questions that come to my mind:
are there any implications in performance by using a flat structure?
what are the advantages of using a nested structure like the mentioned in example #1
which solution is cheaper? (reads/writes)
There are befenits from both the solutions you proposed. Let's dive into them:
performance: they are pretty similar from this point of view. In fact, if you want to get a chat from Firestore, in the second case simply make a query for the messages of a particular chat and parse the required information from the first document you receive (since in each message you have the userID, name, profilePicture, etc ...). With the first approach this operation is straightforward since you already asking for a Chat document.
structure: the first solution is the one that I prefer because it's clear what it does and since Firestore is schemaless it enforces a clear design. With the second approach you are basically flattening your DB but you are also exposing your messages to privacy issues. In fact, setting up rules in the first case is pretty straightforward, simply let the users access only the chats they are involved in. But in this case, all the users can, "possibly", read each other messages which should not be something which you want.
cost: this basically depends on what you will do with these documents. In fact, the cost of Firestore either depended on the number of documents read/written but also on the amount of data you store. Here, the first solution is clearly better since you are not adding redundancy for fields like profilePicture, name, userID, etc ... This fields logically belong to the Chat entity, and not to its messages.
I hope this helps since properly setting up a database is vital for any good project.

DynamoDB or RDS?

I keep going back and forth about choosing DynamoDB or RDS for my project. I understand they are 2 completely different kinds of DB systems, but I am not sure which one would be a better fit for my app. My app alerts users of certain events that happen VERY infrequently.
For instance, an employee may trigger an alert saying that there is an active shooter in the building, so my app needs to get the cell phone numbers of everyone in the company from the database and then use those numbers to send text messages. I just discovered that DynamoDB has a limit of 100 items when retrieving stuff from the database, which is a problem for me because I may have to retrieve 200 or 300 or even more phone numbers as quickly as possible.
In addition to this, the database would not be queried regularly. It would be queried rarely when someone needs to update a user's profile information. of course, it would be queried for users' cell phone numbers in an emergency and I need this to return the results as fast as possible.
It kind of sounds like DynamoDB may be an overkill, but I am not 100 % sure. On the other hand, It seems a PERFECT fit since it can query stuff really quickly, but the limit of 100 items per request just kills me.
To me, there isn't a clear answer in terms of what database system to choose. Based on this use case, what is the best DB option?
You should use AWS pinpoint for that. Pinpoint has endpoints and segments.
The endpoint is email, number... One person in the company can have multiple endpoints.
The segment is a filtered list of endpoints. For example, you can filter endpoints by person title, or by company.
You create Campaign based on segments, so each person in selected segments get email or SMS or both...
Regarding your example, you can create a dynamo DB trigger which will create/update/delete pinpoint endpoints.
AWS approach is not to scan dynamo DB to send group emails or SMS. Instead of that, the approach is to create segment and then create campaigns.

What's the most scalable and performant solution to store chat logs on firebase realtime database?

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.
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?
How about simply using the hash of the resulting concatenation of UIDs?
Alternatively:
Come up with your own unique room key, e.g. using a push ID.
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")

Resources