Firestore Offline Cache & Promises
Firestore Offline Cache & Promises
This question is a follow-up on Firestore offline cache. I've read the offline cache documentation but am confused on one point.
One commenter answered in the prior question (~ year ago):
You Android code that interact with the database will be the same
whether you're connected or not, since the SDK simply works the same."
In the API documentation for DocumentReference's set method, I just noticed that it says:
Returns
non-null Promise containing void
A promise that resolves once
the data has been successfully written to the backend. (Note that it
won't resolve while you're offline).
non-null Promise containing void
Emphasis mine. Wouldn't this bit in the documentation suggest that the code won't behave the same, or am I missing something? If I'm waiting on the .set() to resolve before allowing some user interaction, it sounds from this bit like I need to adjust the code for an offline case differently than I would normally.
The CollectionReference's add method worries me a bit more. It doesn't have exactly the same note but says (emphasis mine):
A Promise that resolves with a DocumentReference pointing to the newly created document after it has been written to the backend.
That is a little more vague as not sure if "backend" in this case is a superset of "cache" and "server" or if it's meant to denote only the server. If this one doesn't resolve, that would mean that the following wouldn't work, correct?
return new Promise((resolve, reject) =>
let ref = firestore.collection(path)
ref.add(data)
.then(doc =>
resolve( id: doc.id, data: data )
)
...
)
Meaning, the .add() would not resolve, .then() would not run, and I wouldn't have access to the id
of the document that was just added. I hope I'm just misunderstanding something and that my code can continue to function as-is both online and offline.
id
@DougStevenson - good point. Thank you for fixing that.
– Tres
Sep 13 '18 at 14:48
1 Answer
1
You have two of concerns here, which are not really related. I'll explain both of them separately.
For the most part, developers don't typically care if the promise from a document update actually resolves or not. It's almost always "fire and forget". What would an app gain to know that the update hit the server, as long as the app behaves the same way regardless? The local cache has been updated, and all future queries will show that the document has been updated, even if the update hasn't been synchronized with the server yet.
The primary exception to this is transactions. Transactions require that the server be online, because round trips need to be made between the client and server in order to ensure that the update was atomic. Transactions simply don't work offline. If you need to know if a transaction worked, you need to be online. Unlike normal document writes, transactions don't persist in local cache. If the app is killed before the transaction completes on the server, the transaction is lost.
Your second concern is about newly added documents where the id of the document isn't defined at the time of the update. It's true that add()
returns a promise that only resolves when the new document exists on the server. You can't know the id of the document until the promise delivers you the DocumentReference
of the new document.
add()
DocumentReference
If this behavior doesn't work for you, you can generate a new id for a document by simply calling doc()
with no arguments instead of add()
. doc()
immediately returns the DocumentReference of the new (future) document that hasn't been written (until you choose to write it). In both the case of doc()
and add()
, these DocumentReference objects contain unique ids generated on the client. The difference is that with doc()
, you can use the id immediately, because you get a DocumentReference immediately. With add()
, you can't, because the DocumentReference isn't provided until the promise resolves. If you need that new document id right now, even while offline, use doc()
instead of add()
. You can then use the returned DocumentReference to create the document offline, stored in the local cache, and synchronized later. The update will then return a promise that resolves when the document is actually written.
doc()
add()
doc()
doc()
add()
doc()
add()
doc()
add()
Very helpful, thank you! 1) Sounds like I need to re-arrange my thinking for offline mode that is different from past experience. In my UI, after adding a document (in "add mode" screen), it switches to "view mode" of that same document. In my current thinking, it does not switch to that new mode until it has confirmation of success. I'll work on switching to fire-and-forget thinking. Q: Would the .catch still fire if there was a problem writing to the cache? 2) I missed that doc() vs. add() distinction. That absolutely solves my problem and gives me a path forward that is offline capable.
– Tres
Sep 13 '18 at 14:58
I don't know what the error handling is like if a cache write fails. That would be very rare (maybe out of disk space?). But I would expect the promise to become rejected. BTW sometimes it's useful to give the user an indicator that their updates are fully synchronized with the server. For example, with a chat room, the user might want to know if everyone else can see their message yet. You can fire and forget that message, but it's a courtesy to the user for them to know what happened to it. Regardless, you wouldn't want to stop them from trying to send more messages.
– Doug Stevenson
Sep 13 '18 at 15:59
Thanks for contributing an answer to Stack Overflow!
But avoid …
To learn more, see our tips on writing great answers.
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
You tagged this question "android", but since native Android development doesn't involve promises, I changed it to "javascript". Native android involves Task objects instead, which are similar, but not the same.
– Doug Stevenson
Sep 13 '18 at 4:39