Blog Infos
Author
Published
Topics
, ,
Published
What’s the problem?

I’m developing a messaging module where any number of users can chat with each other in a single channel, similar to Slack channels or a WhatsApp group.

  1. Users can react and reply to other users’ messages.
  2. Users can delete the message as well, so it’s important to do so in case the user sent something accidentally.
Possible solution

After experimenting with many cases, I found no one-shot solution to remove all trade-offs. Sometimes I lost the ability to add new messages or lost updates in old messages. BUT there is one solution that may require the following precondition and some extra work.

You need at least one predictable field/column in your database.

By predictable, I mean whose value you should know while fetching data. For example, in my data, each message has a timestamp. And its column name is created_at .

  1. Old N records — Another snapshot listener to get messages whose created_at starts before current system time.
  2. Pagination — Same as 2, add more snapshot listener on-demand but based on created_at of oldest record we got from query 2.
// To observe new records being added.
firestoreDb.collection(collectionPath)
.orderBy("created_at", Direction.ASCENDING)
.startAfter(currentTimestamp)
.addSnapshotListener(...)
// To observe last N records
firestoreDb.collection(collectionPath)
.orderBy("created_at", Direction.ASCENDING)
.endBefore(currentTimestamp)
.limitToLast(10) // N = 10
.addSnapshotListener(...)
// To observe last N to 2N records
firestoreDb.collection(collectionPath)
.orderBy("created_at", Direction.ASCENDING)
.endBefore(lastRecordTimestamp)
.limitToLast(10) // N = 10
.addSnapshotListener(...)

Job Offers

Job Offers


    Android Engineer

    American Express
    London
    • Full Time
    apply now

    Senior Android Engineer, Infrastructure

    Peloton
    New York, USA
    • Full Time
    apply now

    Senior Android Engineer

    Peloton Interactive
    New York
    • Full Time
    apply now
Load more listings

OUR VIDEO RECOMMENDATION

Jobs

fun getMessages(...): Flow<List<DocumentChange>> {
return callbackFlow {
...
.addSnapshotListener { snapshot, e ->
if(e != null) close(e)
trySend(snapshot.documentChanges)
}
awaitClose()
}
}
private val messageMap = linkedMapOf<String, MessageItem>()
private fun updateMessagesMap(documents: List<DocumentChange>) {
documents.forEach { documentChange ->
val message = documentChange.document
.toObject(MessageResponse::class.java)
when (documentChange.type) {
Type.ADDED -> {
messageMap[message.id] = message
}
Type.MODIFIED -> {
messageMap[message.id] = message
}
Type.REMOVED -> {
messageMap.remove(message.id)
}
}
}
}
What do you think?

What do you think about this solution? I’d be happy to improve this solution so let me know your ideas and feedback. Also, feel free to reach out to me on Twitter in case of any questions.

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Nowadays authentication has become common in almost all apps. And many of us know…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE

Leave a Reply

Your email address will not be published.

Fill out this field
Fill out this field
Please enter a valid email address.

Menu