Home > Net >  Firestore - Listen all deletions without downloading the entire collection (receiving "modified
Firestore - Listen all deletions without downloading the entire collection (receiving "modified

Time:12-02

Introduction

In order to listen all the docs of my collection that have beed removed, without downloading the entire collection, I am doing the same as commented here.

Rather than deleting docs completely, just add a "deleted: true" property and then listen on the query "db.collection("cities").where("deleted", "==", true)"

Problem

For some reason I don't understand, I am receiving all the "modified" events as "added" from my Firestore listener.

Chat Room Deletions Code

I am implementing a chat list screen with pagination, so I am just fetching old docs when the screen is mounted, and subscribing to all changes that happens on each chat room doc after new Date() (the time in which the screen is mounted).

For "removing" the chat room docs, I am doing the following:

async function deleteChatRoom(chatRoomId, userId) {
  const chatRoomRef = firestore.collection("chats").doc(chatRoomId);
  const chatRoomDoc = await chatRoomRef.get();
  const chatRoomData = chatRoomDoc.data();
  const messagesPath = `${chatRoomRef.path}/messages`;

  // Check that the user is member of the room
  if (!chatRoomData.members[userId]) {
    throw chatErrors.notChatRoomMember();
  }
  
  // Delete all the chatroom messages
  await deleteCollection(messagesPath);

  // Delete the chat room
  await chatRoomRef.update({ 
    deleted: true, <----
    lastMessage: admin.firestore.FieldValue.delete(), // Delete denormalized sensitive data
    modifiedAt: admin.firestore.FieldValue.serverTimestamp(), <----
    read: admin.firestore.FieldValue.delete(), // Delete denormalized sensitive data
  });
}

As you can see, I am updating the "modifiedAt" and "deleted" fields.

Listener Code

With this, what I am trying to reach is being able to listen to all the chat room changes ("lastMessage" field updates, "read" field updates, "deletions"...) that happens after new Date() in the client side, as I commented before. As follows:

export function listenMyChats(
  startAt = undefined,
  onNext,
  one rror
) {
  const currentUserId = getCurrentUser()?.uid;

  if (!currentUserId) {
    throw authErrors.authenticationRequired();
  }

  let query = firestore
    .collection("chats")
    .where("membersArray", "array-contains", currentUserId)
    .orderBy("modifiedAt");

  if (startAt) {
    query = query.startAt(startAt);
  }

  return query.onSnapshot(onNext, one rror);
}

Something that has sense to me, as I am avoiding reading the entire collection when using the field "startAt" and "orderBy(modifiedAt)".

Subscribing code

Then, to handle all and subscribe to the chat room changes, I am doing the following:

const handleChatsChanges = async (querySnapshot) => {
   const changes = querySnapshot.docChanges();

   await Promise.all(
      changes.map(async (change) => {
         if (change.type === "added") {
            // NEW INCOMING CHATS
            console.log("Added");
         } else if (change.type === "modified") {
            // MODIFIED CHATS ("deleted", "read", "lastMessage" fields...) 
            console.log("Modified");
         }
      });
   );
};

useEffect(() => {
  const listener = listenMyChats(
    startAfter.current,
    handleMyChatsChanges,
    handleOnListenMyChatsError
  );

  return () => {
    listener();
  };
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

The main problem I am experiencing is that, instead of getting the document modifications in the "modified" scope, I am getting "added" events... Why is this happening?

I thought that the listeners behavior were to get all the docs that match the query condition (as "added") when subscribing. And that, after this, the "added" scope was only executed when new docs were added to the target collection (matching the query conditions, of course).

So, why am I receiving the docs fields modifications as "added"?

CodePudding user response:

As detailed in the comments above, the problem comes form the fact that the Firestore documents that are modified where not present in the first snapshot, because your listener is applied on the following query:

firestore
    .collection("chats")
    .where("membersArray", "array-contains", currentUserId)
    .orderBy("modifiedAt");  

And when you modify them they are returned by the above query and therefore they are considered as added by the listener.

They would have been considered as modified if, and only if, they were included in the first snapshot returned after setting the listener.

  • Related