DeltaSync
DeltaSync is a way to reduce the amount of conducted data between device and backend. Use our SDKs to simply enable DeltaSync in the Datastore. When you use our REST API directly, you can utilize specific HTTP headers to achieve similar results.
Enable / Disable DeltaSync
DeltaSync is currently implemented in the iOS, C#, Javascript, TypeScript and Android SDKs. We’re working on implementing it within other SDKs.
To enable or disable DeltaSync, you simply need to call a method in the Datastore:
Android
Datastore.getInstance().setUseDeltaSync(
true
);
// Or false
Objective-C
[[[DataStore sharedInstance] config] setDeltaSyncStrategy:DeltaSyncStatesOBJECT_BASED];
// or DeltaSyncStatesCOLLECTION_BASED or DeltaSyncStatesNONE
Swift
DataStore.sharedInstance.config.deltaSyncStrategy = DeltaSyncStates.OBJECT_BASED
// Or DeltaSyncStates.COLLECTION_BASED or DeltaSyncStates.NONE
C#
Datastore.Instance.DeltaSyncStrategy = DeltaSyncStrategy.OBJECT_BASED;
// Or DeltaSyncStrategy.COLLECTION_BASED or DeltaSyncStrategy.NONE
TypeScript
Datastore.Instance.deltaSyncStrategy = AOMDeltaSyncStrategy.COLLECTION_BASED;
// Or AOMDeltaSyncStrategy.OBJECT_BASED or AOMDeltaSyncStrategy.NONE
That’s about it!
DeltaSync is active, reducing the the data quantity conducted between your users’ devices and the backend.
Read on to learn in which cases the use of DeltaSync makes sense.
The Objective-C SDK currently doesn't delete objects from the storage (both persistent storage and cache) although the delta-deleted header contains IDs of objects that should be deleted. This means that when fetching a collection of objects of a class with (or without) a query, you'll get the correct result, but the locally stored single objects still exist and can be loaded.
How does DeltaSync work?
A precondition for DeltaSync to work is an activated offline handling. So cache strategy “NETWORK_ONLY” cannot be used. However, persistent or in-memory storage does not restrict DeltaSync activation.
Let’s outline two cases where DeltaSync kicks in:
In both cases, let’s assume there are two users, each with their own device (A and B) and they fetch objects of a class that’s accessible not by just one user, but by all app users. For example, in a conference app, there’s a class Conference and all conferences get fetched.
Remote deletion
-
There are 10 conferences in the backend: conf0, conf1, …, conf9
-
Device A sends a request to fetch all conferences
-
The response contains all conferences
-
All conferences get stored in the cache on the device
-
Device B deletes conf9.
-
Device A sends another request to fetch all conferences (e.g. if the data was updated in the backend). The request contains which conferences are stored on the client.
-
Now, instead of responding with the 9 remaining conferences (conf0-conf8), the response from the backend contains which conference was deleted. So instead of 9 conferences, just the ID of the deleted conference gets transferred.
-
Device A deletes the conference with the received ID.
-
=> The local data on both devices is up to date.
Remote addition
-
There are 9 conferences in the backend: conf0, conf1, …, conf8
-
Device A sends a request to fetch all conferences
-
The response contains all conferences
-
All conferences get stored in the cache on the device
-
Device B creates a new conference: conf9
-
Device A sends another request to fetch all conferences (e.g. for an update to see if the data has changed in the backend). The request contains which conferences are stored on the device.
-
Now, instead of responding with all 10 conferences (conf0-conf9), the response only contains the missing conference, conf9.
-
Device A stores the received conf9.
-
=> The local data on both devices is up to date.
DeltaSync works just as well In the event of remote addition, deletion, and or combination.
Using DeltaSync with the REST API
To replicate the behavior outlined above, handle two headers when using the REST API directly instead of an SDK:
x-apiomat-delta
x-apiomat-delta-deleted
x-apiomat-delta
This header is sent from the device to the backend. Starting with version 2.4, you can choose between two different formats here: A single timestamp of your last synchronization with the server
x-apiomat-delta: <lastSyncTimestamp> (Example: x-apiomat-delta: "1464946487123")
or a map containing all object IDs on the client with their last modified dates:
x-apiomat-delta: {"<ID>":"<lastModifiedAt>", "<ID>":"<lastModifiedAt>", ...}
(Example: x-apiomat-delta: {"544770fab7605645cdc49da1":"1464946487123", "544770fab7605645cdc49da2":"1464946487456"})
The first approach will keep the HTTP header very small, so this should be used for large data synchronizations, because otherwise the server might reject the request due to header size restrictions.
The second approach is more granular. So for example, when a collection synchronization takes place, and afterwards several individual objects are modified and then loaded by the client, the client will send the individual last modified dates of the object they hold in their cache, so the server knows which modified objects don't have to be included in the response. This can save some data from being transferred.
x-apiomat-delta-deleted
This header contains the IDs of all the deleted objects on the server. Delete these from the local storage and add new objects– those that are in the response body.
x-apiomat-delta-deleted: ["<ID>", "<ID>"]
For example: ["544770fab7605645cdc49da1", "544770fab7605645cdc49da2"]