Sync Rules v2 (legacy docs)
Data Rules vs Sync Rules v2
Data rules are a combination sync rules and Access Control Lists, specified in a single XML document. If your app is currently using sync rules v2 (i.e. where sync rules are specified in a sync_rules.xml
file), we strongly recommend migrating to data rules. Please see this guide which outlines the migration process.
Details matter with sync rules
Sync rules is an advanced feature where implementation details can have a significant impact on app performance, sync performance, as well as the design of your data model.
Please be sure to understand the constraints and implications of your sync rules before deploying them to an environment with active users.
Sync rule reprocessing
When changes to the sync rules are deployed to the backend, all data for that deployment needs to be processed again to take the new sync rules into consideration. Please read more information about sync reprocessing below.
Sync Rules v1
The below details sync rules v2. For documentation on sync rules v1, please read the legacy docs.
Sync rules give developers the ability to determine programmatically what data should be sync to which devices. Sync rules are important in production applications, where devices should only store data that's needed for the app to work for security and performance reasons.
Developers can specify sync rules for their apps by opening the sync_rules.xml
file in OXIDE.
Buckets
Sync rules are defined in terms of buckets. A bucket is used to group together objects to synchronize to one or more users. The goal is to split data into separate buckets to reduce the amount of data synchronized to each user, but to not have so many buckets that sync performance is impacted.
Global buckets
The simplest buckets are global buckets. These buckets are synchronized to all users.
This is typically used for data that stays fairly constant over time, e.g. categories used in drop-down lists.
Models can also have conditions to only synchronize a subset of them:
In some cases, data should only be synchronized to some users, e.g. only to admin users or only to technicians. This is possible by specifying a via
property on the bucket.
More details on the via
attribute will follow later.
Object-specific buckets
Object-specific buckets each have a bucket root which defines the grouping. All objects inside the group must have a direct belongs-to relationship to the root object.
Users are then linked to the bucket roots by a path that traverses one or more relationships (belongs-to or has-many).
As an example suppose that we want to split data by region. Each user belongs to a specific region, and we only want to sync client data to users within the same region.
In this case, we'd define the Region as the root of the bucket. We place clients in the bucket according to the belongs-to relationship, and sync the region bucket to each user.
Suppose clients have additional info that we need to include, e.g. contacts. To include this in the region bucket, it needs an explicit belongs-to relationship to the region.
Here's the updated data model:
And the corresponding Sync Rules:
Same as with global-buckets, we can add conditions on the models:
We can also add conditions on the root object:
Or on the user:
Using via
: in depth
via
: in depthIn the case of object-specific buckets, the via
attribute indicates the path to take from the user object to the root of the bucket. For each user, this path can result in zero, one or many bucket roots.
The via
path can contain any number of belongs-to or has-many relationships, along with an optional condition as a filter on each.
Here are some examples:
Limitation: Number of bucket roots
The number of bucket roots per user may never exceed more than 200.
If it does, the user will not be able to synchronize. Sync performance also degrades as the number of buckets per user increases, so it is recommended to keep this to fewer than 50 per user.
Frequently Changing Bucket Roots - pre v4.24
Older versions of the container (before version 4.24) do not handle changing bucket roots per user efficiently. For this reason, it is recommended to keep the bucket roots mostly static per user. For example, in our earlier example, it is not expected that a user's region
will change often. If however, we use something like current_assignment
as the root, the sync performance will suffer every time current_assignment
changes.
Newer container versions (4.24 and later) handle this more efficiently and do not have this issue.
For global buckets, via
works similarly. However, instead of having separate bucket roots, there is only a single bucket that will be synchronized if the via
field has any results.
Here are some examples:
Synchronizing All Data
During development, it is useful to not have to worry about sync rules, and synchronize everything. This is not recommended for applications in production, unless the app will only ever contain a small number of objects (around 10 000 or less).
It is also possible to synchronize all data only to specific users, by using the via
field.
Conditions
Conditions can be applied to any single field on an object.
The following operators are available:
The following are valid values to compare against:
Advanced Example
Sync Rule Reprocessing
When changes to the sync rules are deployed to the backend, all data for that deployment needs to be processed again to take the new sync rules into consideration. The exact processing time varies based on the app and the server load, but it usually takes around 1-2 seconds per 1000 entries in the Oplog, or half an hour per million entries.
Changes that trigger sync rule reprocessing (when deployed) include:
Changes to models, relationships, and conditions in the sync rules.
Some (rare) changes in the data model, if it changes the meaning of the sync rules. For example, if the model referenced by a relationship used in sync rules changes, reprocessing will be triggered.
White-space changes and comments do not trigger sync rule reprocessing.
OXIDE will present a warning dialog when you deploy changes to a Staging / Production deployment that will trigger sync rule reprocessing.
During sync rule reprocessing, users can proceed to use their apps as usual, however previous sync rules will apply until reprocessing is complete.
This means that in cases where the new version of the code relies on new sync rules being active immediately, you should plan on deploying your code in multiple phases:
Deploy a change containing only the new sync rules, as well as any new models and fields in the data model.
Once sync rule reprocessing is complete, deploy the rest of the changes.
Tip: The reprocessing status for a deployment (including the number of Oplog entries to be processed) can be seen on the "Sync Diagnostics" page in the data browser. You may need to elevate permissions to access this page.
Developer Notes
Here are a few final notes on sync rules for developers:
Once sync rules have been deployed for an app, it will become critically important to update the rules when new models are added to the data model, or if model or relationship names change. Failing to do so will result in queries not showing the necessary data in the view, or logic in the JS failing.
Sync rules affect what data can be accessed in the app via
DB
.OnlineDB
is unaffected by sync rules.Note: this behavior is different for data rules. Please see this section for more details.
Sync rules constraints have a big impact on data model design. It is often useful to create "sync relationships" which are only used for sync rules, but have no other meaning in the data model.
Guidance around using sync rules
A general rule is to sync only the data that is applicable to a specific app. The fewer data synced, the more performant the app will be in general:
Fewer than 10k objects on a device is ideal.
Up to 50k objects synced to a device should work but needs to be tested properly. At these data volumes, the app becomes sensitive to poorly-written and unindexed queries. Be sure to monitor the DB size for increases (in the app diagnostics) to prevent unforeseen performance degradations.
Up to 500k objects synced to a device can work, but even with performant queries the sync performance will become slow. This will be exacerbated if there are a large number of users syncing the same data or if the data changes often. Strongly consider using aggressive archiving strategies, or OnlineDB.
Last updated