Manage Sync Subscriptions
On this page
- What are Subscriptions?
- Subscribe to Object Types
- Permissions
- Manage Subscriptions in Your Client App
- Initial Subscriptions
- Subscribe to Queries
- Subscribe to a Query
- Subscribe to a Query with a Subscription Name
- Wait for a Query Subscription to Sync
- Unsubscribe from a Query
- Manually Manage Subscriptions
- Access the Subscription Set
- Find a Subscription
- Add a Subscription
- Wait for Subscription Changes to Sync
- Check Subscription Set State
- Change Subscription Queries
- Remove Subscriptions
- Performance Considerations
- API Efficiency
- Group Updates for Improved Performance
- Sync RQL Requirements and Limitations
- Indexed Queryable Fields Subscription Requirements
- Unsupported Sync Subscription Query Operators
- List Queries
- Embedded or Linked Objects
Atlas Device Sync uses subscriptions and permissions to determine what data to sync with your client application.
After you open a synced database, you must add subscriptions before you can read to and write from the database.
You can manually add, update, and remove subscriptions to determine which data syncs to the client device. Or you can subscribe to queries instead of or in addition to manually managing subscriptions.
What are Subscriptions?
When you configure Device Sync in Atlas, you specify which fields your client application can query. The SDK tracks these queries through a subscription. When you subscribe to a query, the SDK automatically tracks changes to data matching that subscription, and uploads and downloads relevant data.
Each subscription corresponds to a query on queryable fields for a specific object type. See Queryable Fields in the Device Sync documentation for more information.
For each query subscription, the SDK looks for data matching the query. Data matching the subscription, where the user has the appropriate permissions, syncs between clients and the backend application.
The SDK tracks these queries through a subscription set, which is a collection of subscriptions. You can add, remove, and update subscriptions in the subscription set.
You can construct subscription queries with Realm Query Language (RQL), or one of the SDK-idiomatic query engines.
Important
RQL Support in Sync Subscription Queries
Device Sync does not support the full range of RQL operators when constructing a subscription query. For details about these limitations, refer to Sync RQL Requirements and Limitations.
Subscribe to Object Types
Subscription sets are based on your data model object types. You might have multiple subscriptions if you have many types of SDK objects. You can also have multiple subscriptions on the same object type.
However, note the following if you use relationships or asymmetric objects in your app:
Object Links
You must add both an object and its linked object to the subscription set to see a linked object.
If your subscription results contain an object with a property that links to an object not contained in the results, the link appears to be nil. The SDK does not provide a way to distinguish whether that property's value is legitimately nil, or whether the object it links to exists but is out of view of the query subscription.
Asymmetric Objects
If your app uses Data Ingest to unidirectionally sync asymmetric objects, you cannot create subscriptions for those objects. If your app contains asymmetric objects and non-asymmetric objects in the same database, you can add subscription queries for the non-asymmetric objects.
Permissions
Subscriptions work hand-in-hand with permissions to determine what data to Sync to your client application. The client application only sees the subset of data that matches your subscriptions which also matches the permissions of the logged-in user. For more information about the intersection of subscriptions and user permissions, refer to Write Data to a Synced Database.
This page details how to manage client subscriptions for Device Sync. For information about setting up permissions for Device Sync, see: Device Sync Rules & Permissions.
Manage Subscriptions in Your Client App
In the client application, you add, update, and remove subscriptions to specific queries on the queryable fields. This determines which data syncs to the client device.
You can:
Add subscriptions with an optional subscription name:
You can subscribe to a database query. This automatically adds the subscription to the subscription set.
Manually add a subscription to the subscription set with the subscribe API. Use this API if you need more control over subscriptions for performance optimization or business-logic reasons. See Performance Considerations for more information.
React to subscription state changes.
Update subscriptions with new queries.
Remove individual subscriptions or all subscriptions for an object type.
Subscriptions persist across user sessions unless you unsubscribe from them.
Initial Subscriptions
Before you can read from or write to a synced database, you must provide at least one subscription. Some of the SDK languages provide a dedicated API to make it more convenient to set initial subscriptions. For details, refer to Set Initial Subscriptions.
Subscribe to Queries
To simplify subscription management, the SDK offers APIs to subscribe to and unsubscribe from a query directly. These APIs abstract away the details of manually adding and removing subscriptions. This API is not available for all languages. If your preferred language does not provide this API, refer to Manually Manage Subscriptions.
Important
The Subscribe to Queries API is in Preview
The APIs described here are currently in Preview. These APIs may be subject to change in the future.
Subscribe to a Query
With an authenticated user and a Sync configuration, you can open a synced database and query for the objects you want to read and write. You can subscribe to the query to create a subscription for objects matching the query.
This creates an unnamed subscription and adds it to the subscription set, similar to manually creating a subscription.
Subscriptions persist across user sessions unless you unsubscribe from them.
Tip
If your app works with multiple subscriptions, or if you want to update a subscription, you should add a name when you subscribe to a query. For details, refer to the Subscribe to a Query with a Subscription Name section on this page.
Subscribe to a Query with a Subscription Name
If your app works with multiple subscriptions, or if you want to update a subscription, you should add a name when you subscribe to a query.
You can later use this name to:
Wait for a Query Subscription to Sync
When you subscribe to a query, that query's results do not contain objects until the subscription syncs with Atlas.
If your app creates objects, you may not need to download synced data before the user works with it. However, if your app requires data from Atlas before the user can work with your app, you can specify that the SDK should wait for the subscription query data to sync before proceeding.
Unsubscribe from a Query
You can unsubscribe from a query that you have previously subscribed to. Unsubscribing removes the suscription from the subscription set, similar to manually removing a subscription.
A query results set may still contain objects after calling the unsubscribe method if the subscription set contains another overlapping subscription.
The unsubscribe method returns before objects matching the removed subscription are deleted from the database. Sync continues in the background based on the new set of subscriptions. There is no API to wait for the unsubscribe method to sync with the server.
Manually Manage Subscriptions
As an alternative to the subscribe to a query API, you can manually manage the subscriptions in a subscription set.
You can:
Add subscriptions
React to subscription state change
Update subscriptions with new queries
Remove individual subscriptions or all subscriptions for an object type
Data matching the subscription, where the user has the appropriate permissions, syncs between devices and Atlas.
You can specify an optional string name for your subscription.
When you create a subscription, the SDK looks for data matching a query on a specific object type. You can have multiple subscription sets on different object types. You can also have multiple queries on the same object type.
Access the Subscription Set
You can access the subscription set through the database subscriptions
property. You perform all operations to add, find, update, remove, or watch
subscriptions through this property.
Find a Subscription
You can find a specific subscription in a subscription set. You might want to find a specific subscription:
To avoid adding the same subscription again, which in some languages throws an error.
To update the subscription.
To remove the subscription.
Add a Subscription
Add a subscription in a subscriptions update block. You append each new subscription to the client's SDK subscriptions.
Subscriptions persist across user sessions unless you remove them from the subscription set.
If your app is adding subscriptions for the first time, some SDK languages provide a special parameter to set initial subscriptions or recalculate initial subscriptions on app launch. For details, skip to the set initial subscriptions on this page.
Tip
If your app works with multiple subscriptions, or if you want to update a subscription, you should add a name when you subscribe to a query. For details, refer to the Add a Named Subscription section on this page.
Add Unnamed Subscription
If your app doesn't need to update or remove subscriptions, you can add a subscription without a name.
Add a Named Subscription
If your app might need to update or remove subscriptions, you should add a name when you create a subscription. You can use the name to find and update or remove the appropriate subscription later.
Add Multiple Subscriptions
You can add multiple subscriptions within a subscription update block, including subscriptions of different object types.
Performing query updates requires Atlas to recalculate which documents match the query. We strongly advise designing your application to minimize updates. You can do this by batching additions and changes to the subscription set.
Subscribe to All Objects of a Specific Type
In addition to syncing all objects that match a given query, you can subscribe to all objects of a specific type. You do this by appending a subscription without providing a query.
Set Initial Subscriptions
You must have at least one subscription before you can read from or write to the database. You can bootstrap the database with an initial subscription set when you open it. This ensures your app can start working with the database successfully right away.
At any point after setting initial subscriptions, you can:
Wait for Subscription Changes to Sync
Updating the subscription set on the device is only one component of changing a subscription. After the client app subscription change, the SDK synchronizes with the server to resolve any updates to the data due to the subscription change. This could mean adding or removing data from the synced database.
Adding New Subscriptions
If your app creates objects, you may not need to download synced data before the user works with it. However, if your app requires data from Atlas before the user can work with your app, you can specify that the SDK should wait for the subscription changes to sync before proceeding.
Updating Existing Subscriptions
When you update an existing subscription, this could mean adding new data or removing data from the synced database. If this involves things like changing user permissions to add or remove data, or if your app otherwise makes these changes visible to users in the UI, you may want to wait for subscription changes to update before proceeding with app execution. Otherwise, the changes may appear to the user as unexpected changes to the data set later during "normal" app execution.
Check Subscription Set State
You can check the state of the subscription set through to find out the current status of the subscription set. This provides information about whether Atlas has registered the subscription that is on the device. It does not make any guarantees about the state of the documents matching the subscription.
Note
Subscription State "Complete"
The subscription set state "complete" does not mean "sync is done" or "all documents have been synced". "Complete" means the following two things have happened:
The subscription has become the active subscription set that is currently being synchronized with the server.
The documents that matched the subscription at the time the subscription was sent to the server are now on the device. Note that this does not necessarily include all documents that currently match the subscription.
The SDK does not provide a way to check whether all documents that match a subscription have synced to the device.
Change Subscription Queries
You can change the queries in a subscription set. You might want to do this when business logic dictates syncing a different subset of objects, such as when a user unlocks new features in an app.
Change a named query
Change an unnamed query
When you change a query, consider how it interacts with any other queries that may be in the subscription set. You may need to add or remove other subscriptions, such as:
Adding a new subscription when a change to a query introduces new linked objects
Removing a subscription when an overlapping query inadvertently exposes objects you don't want to sync
Change a Named Subscription
Change an Unnamed Subscription
Remove Subscriptions
To remove subscriptions, you can:
Remove a specific subscription
Remove a named subscription
Remove an unnamed subscription
Remove a subscription by reference
Remove all subscriptions for a specific object type
Remove all unnamed subscriptions
Remove all subscriptions
When you remove a subscription query, the SDK asynchronously removes the synced data that matched the query from the client device.
Remove a Named Subscription
Remove an Unnamed Subscription
Remove a Subscription by Reference
Remove All Subscriptions to an Object Type
Remove All Unnamed Subscriptions
You may want to remove unnamed subscriptions that are transient or dynamically generated, but leave named subscriptions in place.
Remove All Subscriptions
Important
If you remove all subscriptions and do not add a new one, you'll get an error. A database opened with a flexible sync configuration needs at least one subscription to sync with the server.
Performance Considerations
API Efficiency
Adding several subscriptions with the .subscribe()
and .unsubscribe()
APIs described in the Subscribe to Queries section
is less efficient than performing batch updates when you manually
manage subscriptions. On every call to .subscribe()
, the SDK opens a new
update block. For better performance adding multiple
subscriptions, use the subscriptions.update
API described in the
Manually Manage Subscriptions section.
Group Updates for Improved Performance
Every write transaction for a subscription set has a performance cost. If you need to make multiple updates to a database object during a session, consider keeping edited objects in memory until all changes are complete. This improves sync performance by only writing the complete and updated object to your database instead of every change.
Sync RQL Requirements and Limitations
Indexed Queryable Fields Subscription Requirements
Adding an indexed queryable field to
your App can improve performance for simple queries on data that is strongly
partitioned. For example, an app where queries strongly map data to a device,
store, or user, such as user_id == $0, “641374b03725038381d2e1fb”
, is
a good candidate for an indexed queryable field. However, an indexed
queryable field has specific requirements for use in a query subscription:
The indexed queryable field must be used in every subscription query. It cannot be missing from the query.
The indexed queryable field must use an
==
orIN
comparison against a constant at least once in the subscription query. For example,user_id == $0, "641374b03725038381d2e1fb"
orstore_id IN $0, {1,2,3}
.
You can optionally include an AND
comparison as long as the indexed
queryable field is directly compared against a constant using ==
or IN
at least once. For example, store_id IN {1,2,3} AND region=="Northeast"
or store_id == 1 AND (active_promotions < 5 OR num_employees < 10)
.
Invalid Device Sync queries on an indexed queryable field include queries where:
The indexed queryable field does not use
AND
with the rest of the query. For examplestore_id IN {1,2,3} OR region=="Northeast"
is invalid because it usesOR
instead ofAND
. Similarly,store_id == 1 AND active_promotions < 5 OR num_employees < 10
is invalid because theAND
only applies to the term next to it, not the entire query.The indexed queryable field is not used in an equality operator. For example
store_id > 2 AND region=="Northeast"
is invalid because it uses only the>
operator with the indexed queryable field and does not have an equality comparison.The query is missing the indexed queryable field entirely. For example,
region=="Northeast
ortruepredicate
are invalid because they do not contain the indexed queryable field.
Unsupported Sync Subscription Query Operators
Device Sync does not support all RQL operators when creating your subscription queries. When you write the query subscription that determines which data to sync to the device, the server does not support these query operators. However, you can use all RQL operators to query the data set once it has synced to the client application.
Operator Type | Unsupported Operators |
---|---|
Aggregate Operators | @avg , @count , @max , @min , @sum |
Query Suffixes | DISTINCT , SORT , LIMIT |
Case insensitive queries ([c]
) cannot use indexes effectively.
As a result, case insensitive queries are not recommended, since they could lead to
performance problems.
Device Sync only supports @count
for array fields.
List Queries
Device Sync supports querying lists using the IN
operator.
You can query a list of constants to see if it contains the value of a queryable field:
// Query a constant list for a queryable field value "priority IN { 1, 2, 3 }"
If a queryable field has an array value, you can query to see if it contains a constant value:
// Query an array-valued queryable field for a constant value "'comedy' IN genres"
Warning
You cannot compare two lists with each other in a Device Sync query. Note that this is valid Realm Query Language syntax outside of Device Sync queries.
// Invalid Flexible Sync query. Do not do this! "{'comedy', 'horror', 'suspense'} IN genres" // Another invalid Flexible Sync query. Do not do this! "ANY {'comedy', 'horror', 'suspense'} != ANY genres"
Embedded or Linked Objects
Device Sync does not support querying on properties in Embedded Objects
or links. For example, obj1.field == "foo"
.