Firebase - Change data before being sent from cache to server - swift

I am using Firebase for my chat application I am developing with Swift. I have offline persistence enabled, so normally each query is first cached and then sent to the server. What I want to do is, when sending a message, have the message status first set to "Sending" and the time to current time, but when the data is sent to the server, change the status to "Sent" and the time to when the data was sent (because it could be minutes to whatever if there's slow connection or no connection at all). Is this possible using Firebase? If not, any workarounds? Thanks in advance!

In Cloud Firestore you can detect the status of your write operations by:
attaching a completion listener to the write operation
looking at the metadata of document snapshots
For the first step, have a look at the example of writing a document in the documentation. The completion listener there allows you to detect when the write operation is completed.
But if you want to show in the UI for each document you show whether it has pending writes that have not yet been committed on the server, you might be better off looking at the metadata of each document snapshot. As explained in the documentation in events for local changes. While the changes are pending, the snapshot.getMetadata().hasPendingWrites() will return true. Then once the changes are committed on the server, it will return false again.

Related

General question: Firestore offline persistence and synchronization

I could not find detailed information in the documentation. I have several questions regarding the offline persistence of firestore.
I understood that firestore locally caches everything and syncs back once online. My questions:
If I attach an onCompleteListener to my setDocument method it only fires when the device is online and has network access. But with offline persistence enabled, how can I detect that data has successfully been written to the cache (Is it always successful?!) - I see data is immediatly there without any listener ever triggering.
What if I wrote data to the cache while the device is offline then comes back online and everything gets synched. What if now any sort of error happens (So the onSuccessListener would contain an error, but the persistence cache already has the data). How do I know that offline and online data are ALWAYS in sync once network connection is restored on all devices?
What about race conditions? Lets say two users update a document at the "same time" while the device is offline. What happens once it comes back online?
But the most pressing question is: right now I continue with my programflow when the onSuccessListener fires, but it never does as long as the device is offline (showing an indefinete progress bar forever). I still need to continue with my program (thats why we have offline persistence) - How do I do this?
How can I detect that data has successfully been written to the cache
This is the case when the statement that write the data has completed. If writing to the local cache fails, an exception is thrown from that write statement.
You second point is hard to summarize, but:
Firestore keeps the pending writes separate from the snapshots it returns for local reads, and will update the cached snapshot correctly both for successful and for rejected writes.
If you want to know whether the snapshot you read contains any pending writes, you can check the pendingWrites field in its metadata.
What about race conditions? Let's say two users update a document at the "same time" while the device is offline. What happens once it comes back online?
The last write wins. If that's not what you need, use security rules to enforce your requirements on the server.

Can a Firestore publisher detect subscriptions from listeners?

Can a Firestore client detect subscriptions to a document? I want a client to only publish (write) document changes if at least one other client is listening to that document. In my case, this would dramatically reduce the number of Firestore writes across the database.
Scenario:
a client is sampling a measured value every 3 seconds and publishing this to Firestore
another client (an app) is listening to this Firestore document and displaying the value updates
the app is only open on occasion, when the user wants to view the data. Most of the time it is not open, and thus no clients are listening to that document
Is there any way in the Firestore API to detect if a document is being listened to?
No, that's not possible. Code that writes a document will do so unconditionally. You can't arrange for a write to happen if there are no listeners, and you can't find out if there are any listeners at all. You will need some other (much more complex system) set up to do something like that.
As Doug said, there is nothing built in to Firestore to detect whether there are listeners on the data. The closest I can think of is the presence system that is (sort of) built into Firebase's other database (Realtime Database), but that doesn't exist on Firestore (yet, an Extension is in the works for it).
But even on that you'd probably need to do some extra work, to track specifically what collection(s) each client is listening to. It'd boil down to:
When attaching an observer, also record that observer in the Realtime Database. At the same time register an onDisconnect handler for this node, so that it automatically gets deleted when the client disconnects.
When detaching an obersver, remove its record from the Realtime Database and remove the onDisconnect handler.
Now in your publisher app, you can detect how many observers there are to each collection.

MongoDB: Ensure data is delivered and delivered only once

I have a theoretical problem with MongoDB:
I have an API that reads data from a MongoDB database. We have to make sure that each item in the collection is delivered eventually, but only once after it was inserted or changed. So the client needs the most recent version of the items, but only once, we must never send an item again if there was no change to it.
We first thought to achieve this by using a date: The client sends the date of the last query and we will only deliver the items that were created or changed after that date. The problem that I see is that we might miss items if part of the cluster is not available for some time and did not get synchronized with the rest. These items will never be delivered (as they were created after the last sync, did not sync with the rest and the client now has a newer "last fetched" time).
As this will not work, I thought about solving this with some kind of ACK-Flag, which is false on creation and true after it was sent to the client. After a change it would be set to false again. Here I see the problem that if someone changes the item while it is currently being sent to the client this change might be missing afterwards (the change says ACK=false, but the delivery says ACK=true afterwards).
This again does not seem to work as intended, so now I am thinking about some kind of optimistic locking where I store a version in the DB and update the ACK=true only if the version did not change from reading to writing.
This should work, but does not seem optimal at all (what if the call crashes while writing the ACK?). As this seems to be a common problem: What would be the best solution to this? Or is MongoDB just not the right tool for the job? Is it even possible to solve this if you expect that you have to scale vertically at some point?

Check if object has been synced to the Realm Object Server

Is there a way to check if the new object/edited object has been synced yet? I need to put an indicator that shows if the edited object has been successfully synced or is still only saved locally. I'm using Realm Object Server v1.0.
This information isn't available at an object level granularity due to the way that synchronization works. Synchronization processes transactions at a time. You can use SyncSession.addProgressNotification(for:mode:block:) with the forCurrentlyOutstandingWork progress mode to be notified when the changes made in a given write transaction have been uploaded.

AFIncrementalStore - best design to prevent some records from being updated

Here is the use case:
I am using AFIncrementalStore, in a fairly standard way
When offline, user is still able to update some records
I set up my own queue to upload edited records and process the queue when back online
When back Online I also refetch data
I want to make sure that my updated records don't get re-updated with the old data from the server when back online
Whenever I edit a record, I flag it in core data as 'edited', and clear the flag only when it is successfully sent to server
The goal is:
when I get results from server, if the results already exist in core
data, but are flagged as 'updated' or 'deleted', I don't want them to
be refreshed with values from the server
I am looking for the best design to achieve that, out of the box if possible. I would like to avoid subclassing.