Raul
Raul

Reputation: 3081

Firestore query onSnapshot is returning me all previous docs on each change

I am adding docs to a collection of messages. For getting real time updates in my UI, I am listening to new docs that have been created after "new Date()".

The thing is that, after getting the first snapshot with all the documents that match the query, when a new doc is added, I am receiving all the previous detected docs in the listener.

Is this the expected behavior?? What am I doing wrong?

This is what I am doing:

    export function listenNonDeletedChatMessages(
      chatRoomId,
      startAt = undefined,
      onMessageReceived = undefined,
      onNext = undefined,
      onError = undefined
    ) {
      const currentUser = getCurrentUser();
    
      if (!currentUser) {
        throw authErrors.authenticationRequired();
      }
    
      let query = firestore
        .collection("chats")
        .doc(chatRoomId)
        .collection("messages")
        .where("content.deletedAt", "==", null)
        .orderBy("date");
    
      if (startAt) {
        query = query.startAt(startAt);
      }
    
      return query.onSnapshot(handleChanges, onError);
    
      function handleChanges(querySnapshot) {
        const messages = [];
    
        querySnapshot.docs.forEach((doc) => { // I am getting N docs on each change, why? 
          const messageData = {
            id: doc.id,
            ...doc.data(),
          };
    
          const parsedMessage = parseChatMessage(
            messageData,
            currentUser.uid
          );
    
          console.log(messageData); <--- this method is logging me all the already detected docs!
    
          messages.unshift(parsedMessage);
    
          onMessageReceived?.(parsedMessage);
        });
    
        querySnapshot.docChanges().forEach((change) => { // 1 change detected, as expected
          console.log(change.type); <--- THIS ONLY LOGS "added" one time when a doc is added!
        });
    
        onNext?.(messages);
      }
    }

Note: I am not talking about the initial status, where all docs are fetched, I am saying that I am receving the same docs again and again on any new doc addition, while they are not being modified.

Upvotes: 2

Views: 1550

Answers (2)

Raul
Raul

Reputation: 3081

Based on Frank Solution, in order to avoid getting same docs of the query, doing something like this will work:

export function listenNonDeletedChatMessages(
  chatRoomId,
  startAt = undefined,
  onMessageReceived = undefined,
  onNext = undefined,
  onError = undefined
) {
  const currentUser = getCurrentUser();

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

  let query = firestore
    .collection("chats")
    .doc(chatRoomId)
    .collection("messages")
    .where("content.deletedAt", "==", null)
    .orderBy("date");

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

  return query.onSnapshot(handleChanges, onError);

  function handleChanges(querySnapshot) {
    const messages = [];

    querySnapshot.docChanges().forEach((change) => {
      if (change.type === "added") {
        const messageData = {
          id: change.doc.id,
          ...change.doc.data(),
        };

        const parsedMessage = parseChatMessage(
          messageData,
          currentUser.uid
        );

        messages.unshift(parsedMessage);

        onMessageReceived?.(parsedMessage);
      };
    });

    onNext?.(messages);
  }
}

Upvotes: 0

Frank van Puffelen
Frank van Puffelen

Reputation: 598837

That is the expected behavior: the QuerySnapshot contains information about all documents that match the query, not just about the changes.

If you want to process all documents, loop over docs as you do first in your code.

If you want to process only the changes, loop over docChanges as you do later in your code.

Upvotes: 5

Related Questions