I'm building a wep app with Firebase / Firestore.
At startup, my app waits for settings to be loaded from Firestore. Then my app is listening for changes from Firestore.
For the first load, I use .getDoc()
because it returns a promise. I need to be sure data is loaded before moving forward.
For listening continuously, I use .onSnapshot()
At startup, my app query twice the database: one for .getDoc()
and one for .onSnapshot()
. Indeed, when you call .onSnapshot()
, the first query is performed instantaneously.
Obviously, I prefer to avoid clients making two identical requests to Firestore. To prevent requesting twice the same data from Firestore, I created a global variable firstSettingsFromDB
that become true once the callback function of .onSnapshot()
is called.
Then, in my boot sequence, I created a function that poll my variable firstSettingsFromDB
until it becomes true, then I can resolve a promise.
// Polling until the first settings are fetched from DB
let polling = setInterval(() => {
// ... check if settings are loaded from DB
if (this.firstSettingsFromDB) {
clearInterval(polling);
resolve();
}
}, 50)
My problem is now that I have the same issue with user data. But user data is not a document, it is a collection. So I need to fetch a collection at startup and being sure the full collection is loaded before moving forward. Then I listen for changes. I can't use polling for my collection since I don't know a priori what the size of the collection is.
Finally, I'm not satisfied by any of these solutions:
I already read dozen of documentation about this topic, but I can't find a satisfying solution.
I can't figure out how to fetch a collection at startup before mowing forward and then listen for changes properly. I'm beginning to wonder if there isn't a design flaw in the Firestore libraries?
I realized that .onSnapshot()
queries the full collection at once. However, I still don't like the polling mechanism.
As you've noticed, "the first query snapshot contains added events for all existing documents that match the query (or collection)". (Excerpt from the blue background note in this section of the doc)
If you want to know when the entire set of documents is loaded for the first time, just trigger an action in the callback function when it is the first time the callback function is called.
For example:
let count = 0;
const q = query(collection(db, "cities"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
count++;
if (count === 1) {
// First load!!
// Do whatever you want here, e.g. "move forward"
}
querySnapshot.forEach((doc) => {
// ...
});
});