Why Is Firestore's 'doc.get('time').tomillis' Producing A Null Type Error?
Solution 1:
The problem you encounter is caused by the onSnapshot()
listener firing from the local Firestore cache during a small window where the value of firebase.firestore.FieldValue.serverTimestamp()
is considered pending and is treated as null
by default. Once the server accepts your changes, it responds with all the new values for the timestamps and triggers your onSnapshot()
listener again.
Without care, this may cause your app to 'flicker' as it stamps the data out twice.
To change the behaviour of pending timestamps, you can pass a SnapshotOptions
object as the last argument to doc.data()
and doc.get()
as appropriate.
The following code, instructs the Firebase SDK to estimate the new timestamp values based on the local clock.
const estimateTimestamps = {
serverTimestamps: 'estimate'
}
querySnapshot.forEach((doc) => {
const msg = doc.data(); // here msg.time = null
msg.docId = doc.id;
msg.time = doc.get('time', estimateTimestamps).toMillis(); // update msg.time to set value (or estimate if not available)
messages.push(msg);
});
If you want to show that your message is still being written to the database, you could check if msg.time
is null
just before estimating the timestamp.
const estimateTimestamps = {
serverTimestamps: 'estimate'
}
querySnapshot.forEach((doc) => {
const msg = doc.data(); // here msg.time = null when pending
msg.docId = doc.id;
msg.isPending = msg.time === null;
msg.time = doc.get('time', estimateTimestamps).toMillis(); // update msg.time to set value (or estimate if not available)
messages.push(msg);
});
If you want to ignore these intermediate 'local' events in favour of waiting for the server's full response, you would use:
.onSnapshot({includeMetadataChanges: true}, (querySnapshot) => {
if (querySnapshot.metadata.fromCache && querySnapshot.metadata.hasPendingWrites) {
return; // ignore cache snapshots where new data is being written
}
const messages = [];
querySnapshot.forEach((doc) => {
const msg = doc.data();
msg.docId = doc.id;
msg.time = doc.get('time', estimateTimestamps).toMillis();
messages.push(msg);
});
dispatch({ type: types.LOAD_MSGS, payload: messages });
resolve();
});
In the above code block, note that I also checked querySnapshot.metadata.hasPendingWrites
before ignoring the event so that when you first load up your app, it will print out any cached information immediately. Without this, you will show an empty message list until the server responds. Most sites will print out any cached data while showing a throbber at the top of the page until the server responds with any new data.
Post a Comment for "Why Is Firestore's 'doc.get('time').tomillis' Producing A Null Type Error?"