2

Client-side, I'm using a listener to detect if the "notifications" collection of the user changes. The App calls a Cloud Function that retrieves the last three unread notifications and the total number of unread notifications.

In my App, I have this:

Listener

      firestore.collection("users")
                .doc(uid)
                .collection("notifications")
                .snapshots().listen((QuerySnapshot querySnapshot) {
                     NotificationsPreviewModel notificationsPreview =
                  await _cloudFunctionsService.getNotificationsPreview(doctor.id)
        })

Cloud Function

    exports.getNotificationsPreview = functions.https.onCall(async (data, context) => {
        const userId = data.userId;
        let notifications = [];
    
        const notificationsDocuments = await db
            .collection("users")
            .doc(userId)
            .collection("notifications")
            .orderBy("dateTime", "desc")
            .get();
    
        notifications = notificationsDocuments.docs.map((rawNotification) =>
            rawNotification.data()).filter((element) => element.unread == true);
    
        const notificationsNumber = notifications.length;
        notifications = notifications.slice(0, 3);
    
        return { "notifications": notifications, "notificationsNumber": notificationsNumber };
    });

The Cloud Function gets called only when a change is detected, so it shouldn't return old data.

The error appears only the first time the Cloud Function is called from the App's start, but not always. The following calls don't generate the error.

How can I solve this? For now, I've added a delay of 500ms, and it works perfectly, but it's not a real solution.

Andrew
  • 795
  • 4
  • 18
Emanuele Vinci
  • 596
  • 1
  • 5
  • 17

2 Answers2

1

Based on your description, it sounds like you see some form of latency while collecting the data from Firestore. Retrieving data from the Cloud takes time, and a delay of 500ms is not excessive.

I am not familiar with Flutter enough to comment on your code. However, according to the documentation for Java:

By default, get() attempts to provide up-to-date data when possible by waiting for data from the server, but it may return cached data or fail if you are offline and the server cannot be reached. This behavior can be altered via the Source parameter.

Source:

By providing a Source value, these methods can be configured to fetch results only from the server, only from the local cache, or attempt to fetch results from the server and fall back to the cache (which is the default).

If you are online, get() checks the server for the latest data, which can take between 300ms and 1500ms depending on several factors. For example, where is your Firestore instance located in comparison to your Cloud Function and client? Try adjusting the delay and see if you can identify the timing.

There are also some soft limits you should be aware of as this might also impact your timings for how quickly you can retrieve the data. There is a maximum sustained write rate to a document of 1 per second. Sustaining a write rate above once per second increases latency and causes contention errors.

Andrew
  • 795
  • 4
  • 18
  • Source options are not supported in the Node.js SDK, becouse it doesn't have the offline support (it's always online). I'll work on a workaraound. – Emanuele Vinci Oct 21 '21 at 09:24
0

As for the documentation:

When you set a listener, Cloud Firestore sends your listener an initial snapshot of the data, and then another snapshot each time the document changes.

It seems that you are initially receiving the snapshot of the data, and then the following updates, as expected.

You can check some possible solutions to this in this post.

JMA
  • 803
  • 4
  • 9
  • If I receive the initial snapshot the function is triggered and the Cf is called, but it's not my problem. The problem is that at the first change the CF returns old data, so it's not the first snapshot, but the first when a change in my collection occours – Emanuele Vinci Oct 12 '21 at 13:51