Docs Menu

Docs HomeRealm

Manage Flexible Sync Subscriptions - Node.js SDK

On this page

  • Overview
  • Subscribe to Queryable Fields
  • Get Subscriptions
  • Add a Query to the List Of Subscriptions
  • Bootstrap the Realm with Initial Subscriptions
  • Check the Status of Subscriptions
  • Update Subscriptions with a New Query
  • Remove Subscriptions
  • Remove a Subscription by Query
  • Remove a Subscription by Name
  • Remove a Subscription by Reference
  • Remove All Subscriptions on an Object Type
  • Remove All Subscriptions
  • Flexible Sync RQL Limitations
  • Unsupported Query Operators in Flexible Sync
  • List Queries
  • Embedded or Linked Objects

Flexible Sync uses subscriptions and permissions to determine which data to sync with your App.

To use Flexible Sync in a Node.js client:

You can add, update, and remove query subscriptions to determine which data syncs to the client device.

Note

Flexible Sync Prerequisites

Enabling Flexible Sync in your App requires a non-sharded Atlas cluster running MongoDB 5.0 or greater

Note

Realm JS SDK Version Requirement

In addition to the requirements above, you must use Realm JS version 10.12.0 or greater in order to use Flexible Sync in your Node.js client application.

Important

Flexible Sync Query Limitations

You cannot use all queries with Flexible Sync subscriptions. Refer to the Flexible Sync RQL Limitations documentation for information on which query types are not supported.

When configuring Flexible Sync on the backend, you specify which fields your client application can query. In the client application, use the Subscriptions API to manage a set of subscriptions to specific queries on queryable fields.

You can:

  • Get a list of all subscriptions

  • Add subscriptions

  • Check subscription state

  • Update a subscription with a new query

  • Remove individual subscriptions or all subscriptions of a type

When data matches the subscription and has appropriate permissions, it syncs between devices and the backend application.

A Realm subscription in JavaScript has:

  • A created and updated date

  • A name

  • An object type

  • A query string

You can specify a string name for your subscription. If you do not give your subscription a name, the name is set to null.

When you create a subscription, Realm looks for data matching a query on a specific object type. In your Flexible Sync subscriptions, you can have subscriptions on several different object types or several queries on the same object type.

Example

In the following example, queries are created to subscribe to:

  • A filtered list of completed tasks that have taken over 120 progressMinutes

  • A filtered list of completed tasks

Notice that queries that you subscribe to using Flexible Sync are syntactically the same as querying a realm and that the queries below will create an overlapping result set.

const tasks = realm.objects("Task");
const longRunningTasks = tasks.filtered(
'status == "completed" && progressMinutes > 120'
);
const bensTasks = tasks.filtered('owner == "Ben"');

Important

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 null. There is no way to distinguish whether that property's value is legitimately null, or whether the object it links to exists but is out of view of the query subscription.

When using a flexible synced realm, you can access a SubscriptionSet, a collection of subscriptions, through the realm.subscriptions property.

// get the SubscriptionSet for the realm
const subscriptions = realm.subscriptions;

You can use this SubscriptionSet to add queries to the list of subscriptions and update existing subscriptions, as shown in the examples below.

Compose queries to add to your Flexible Sync subscriptions using the query engine:

const tasks = realm.objects("Task");
const longRunningTasks = tasks.filtered(
'status == "completed" && progressMinutes > 120'
);
const bensTasks = tasks.filtered('owner == "Ben"');

Add queries to your subscriptions list to sync the query's data. To do so, perform the following:

  1. Create a transaction by passing a callback function to the SubscriptionSet.update() method of your SubscriptionSet. The callback function provides a MutableSubscriptionSet as an argument.

  2. Within the callback function, call the add() method on the MutableSubscriptionSet to add a query to the subscription.

The following example shows how to subscribe to the queries created above.

await realm.subscriptions.update((mutableSubs) => {
mutableSubs.add(longRunningTasks, {
name: "longRunningTasksSubscription",
});
mutableSubs.add(bensTasks);
mutableSubs.add(realm.objects("Team"), {
name: "teamsSubscription",
throwOnUpdate: true,
});
});

The add() method on the MutableSubscriptionSet takes a query and a SubscriptionOptions object. The subscription options include:

  • a name string field

  • a throwOnUpdate boolean field.

If throwOnUpdate is false or undefined, adding a subscription with an existing name will replace the existing query with the new query. However, if you set throwOnUpdate to true, adding a subscription with an existing name but a different query throws an exception.

New in version 10.18.0.

You must have at least one subscription before you can read from or write to a realm with Flexible Sync enabled. You can bootstrap a realm with an initial subscription set when you open it with a SyncConfiguration and Flexible Sync enabled. Include the initialSubscriptions field into the SyncConfiguration. Within the initialSubscriptions object, add an update field set to a callback in which you can subscribe to queries to bootstrap your application:

const config = {
sync: {
user: app.currentUser,
flexible: true,
initialSubscriptions: {
update: (subs, realm) => {
subs.add(
realm.objects("Team").filtered("name == 'Developer Education'")
);
},
},
},
};
const realm = await Realm.open(config);

You can check the subscription state to see if the server has acknowledged the subscription and the device has downloaded the data locally.

You can use subscription state to:

  • Trigger error handling

  • Show if the transaction is pending or has completed

  • Find out when a subscription set is superseded, and you should obtain a new instance of the subscription set to write a subscription change

To the status of subscriptions, log the value of the subscription's state.

console.log(realm.subscriptions.state); // log the subscription state

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 local device. Note that this does not necessarily include all documents that currently match the subscription.

The Realm SDK does not provide a way to check whether all documents that match a subscription have synced to the device.

You can update a named subscription with a new query. To update a subscriptions query, pass the new query and a subscription option with the name of the subscription that you want to update to the MutableSubscriptionSet.add() method. Like adding a new subscription, you must update a subscription within a transaction by calling subscriptions.update() method.

In the following example, long-running tasks are re-defined to be any tasks that have taken more than 180 minutes.

realm.subscriptions.update((mutableSubs) => {
mutableSubs.add(
tasks.filtered('status == "completed" && progressMinutes > 180'),
{
name: "longRunningTasksSubscription",
}
);
});

Note

Attempting to update a subscription that has the SubscriptionOptions.throwOnUpdate field set to true, throw an exception.

To remove subscriptions from the subscription set, you can:

  • Remove a single subscription with the given query

  • Remove a single subscription with the given name

  • Remove all subscriptions on a specific type

  • Remove all subscriptions

When you remove a subscription query, the server also removes synced data from the client device.

You can remove a specific subscription by query by executing a transaction on the subscriptions set. Pass the query to the remove() method on the MutableSubscriptionSet within a transaction.

In the following example, the subscription to tasks with an owner named 'Ben' is removed from the subscriptions set.

realm.subscriptions.update((mutableSubs) => {
// remove a subscription with a specific query
mutableSubs.remove(tasks.filtered('owner == "Ben"'));
});

To remove a specific subscription by name, execute a transaction on the subscriptions set. Within the transaction, pass the name to the removeByName() method on the MutableSubscriptionSet.

realm.subscriptions.update((mutableSubs) => {
// remove a subscription with a specific name
mutableSubs.removeByName("longRunningTasksSubscription");
});

If you have a reference to a subscription, you can remove that subscription. To do so, execute a transaction on the subscriptions set. Within the transaction, pass the reference variable to the removeSubscription method on the MutableSubscriptionSet.

let subscriptionReference;
realm.subscriptions.update((mutableSubs) => {
subscriptionReference = mutableSubs.add(realm.objects("Task"));
});
// later..
realm.subscriptions.removeSubscription(subscriptionReference);

To remove all subscriptions on a specific object type, execute a transaction on the subscriptions set. Within the transaction, pass the object type as a string to the removeByObjectType method on the MutableSubscriptionSet.

realm.subscriptions.update((mutableSubs) => {
mutableSubs.removeByObjectType("Team");
});

To remove all subscriptions from the subscriptions set, execute a transaction on the subscriptions set. Call removeAll() on the MutableSubscriptionSet within the transaction

realm.subscriptions.update((mutableSubs) => {
mutableSubs.removeAll();
});

Flexible Sync has some limitations when using RQL operators. When you write the query subscription that determines which data to sync, the server does not support these query operators. However, you can still use the full range of RQL features to query the synced data set in 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.

Flexible Sync only supports @count for array fields.

Flexible 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 Flexible Sync query. Note that this is valid Realm Query Language syntax outside of Flexible 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"

Flexible Sync does not support querying on properties in Embedded Objects or links. For example, obj1.field == "foo".

←  Configure & Open a Synced Realm - Node.js SDKManage a Sync Session - Node.js SDK →
Share Feedback
© 2023 MongoDB, Inc.

About

  • Careers
  • Investor Relations
  • Legal Notices
  • Privacy Notices
  • Security Information
  • Trust Center
© 2023 MongoDB, Inc.