Docs Menu

Docs HomeRealm

Manage Sync Subscriptions - Kotlin SDK

On this page

  • Prerequisites
  • Subscriptions
  • Add a Subscription
  • Wait for Subscription Changes to Sync
  • Subscription Set State
  • Update Subscriptions with a New Query
  • Remove Subscriptions
  • Remove a Single Subscription
  • Remove All Subscriptions to 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 the SDK:

  • Configure Flexible Sync on the backend

  • Authenticate a user in your client app.

  • Open the synced Realm with a Flexible Sync configuration

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

When you configure 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 construct queries with Realm Query Language.

Important

Flexible Sync does not support all the operators available in Realm Query Language. See Flexible Sync RQL Limitations for details.

You can:

  • Add subscriptions

  • React to subscription state

  • 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 clients and the backend application.

You can specify an optional string name for your subscription.

Tip

Always Specify a Subscription Name

Always specify a subscription name if your application uses multiple subscriptions. This makes your subscriptions easier to look up, update, and delete elsewhere in your app.

When you create a subscription, Realm looks for data matching a query on a specific object type. You can create multiple subscription sets on different object types, and even query multiple times on the same object type.

Subscription names must be unique. Adding a subscription with the same name as an existing subscription throws an error.

Add a subscription in a subscriptions update block. You append each new subscription to the client's Realm subscriptions.

realm.subscriptions.update {
this.add(
realm.query<Toad>("name == $0", "another name value"),
"another subscription name"
)
}

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.

Writing an update to the subscription set locally is only one component of changing a subscription. After the local subscription change, the client 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 realm. Use the SynConfiguration.waitForInitialRemoteData() builder method to force your application to block until client subscription data synchronizes to the backend before opening the realm:

// make an update to the list of subscriptions
realm.subscriptions.update {
this.add(
realm.query<Toad>("name == $0", "another name value"),
"another subscription name"
)
}
// wait for subscription to fully synchronize changes
realm.subscriptions.waitForSynchronization(Duration.parse("10s"))

You can also use SubscriptionSet.waitForSynchronization() to delay execution until subscription sync completes after instantiating a sync connection.

Use the SubscriptionSet.state property to read the current state of the subscription set.

SUPERCEDED (sic -- note alternate spelling) is a SubscriptionSetState that can occur when another thread writes a subscription on a different instance of the subscription set. If the state becomes SUPERCEDED, you must obtain a new instance of the subscription set before you can write to it.

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 subscriptions using SubscriptionSet.update(). In this example, we use MutableSubscriptionSet.add(). to update the query for the subscription named "subscription name". You must set the updateExisting parameter to true to update a subscription with add():

// create an initial subscription named "subscription name"
val config = SyncConfiguration.Builder(user, setOf(Toad::class))
.initialSubscriptions { realm ->
add(
realm.query<Toad>(
"name == $0",
"name value"
),
"subscription name"
)
}
.build()
val realm = Realm.open(config)
// to update that subscription, add another subscription with the same name
// it will replace the existing subscription
realm.subscriptions.update {
this.add(
realm.query<Toad>("name == $0", "another name value"),
"subscription name",
updateExisting = true
)
}

You cannot update subscriptions created without a name. However, you can look up unnamed subscriptions by their query, remove them from the subscription set, then add a new subscription with an updated query:

val subscription =
realm.subscriptions.findByQuery(
realm.query<Toad>("name == $0", "name value")
)
if (subscription != null) {
realm.subscriptions.update {
this.remove(subscription)
this.add(
realm.query<Toad>(
"name == $0",
"another name value"
),
"subscription name"
)
}
}

To remove subscriptions, you can:

  • Remove a single subscription query

  • Remove all subscriptions to a specific object type

  • Remove all subscriptions

When you remove a subscription query, Realm asynchronously removes the synced data that matched the query from the client device.

You can remove a specific subscription query using MutableSubscriptionSet.remove(). You can either look up the subscription by name, then pass the returned subscription to remove(), or pass the subscription name directly to remove():

// create an initial subscription named "subscription name"
val config = SyncConfiguration.Builder(user, setOf(Toad::class))
.initialSubscriptions { realm ->
add(
realm.query<Toad>(
"name == $0",
"name value"
),
"subscription name"
)
}
.build()
val realm = Realm.open(config)
// remove subscription by name
realm.subscriptions.update {
this.remove("subscription name")
}

If you want to remove all subscriptions to a specific object type, pass a class to the MutableSubscriptionSet.removeAll(). method:

// create an initial subscription named "subscription name"
val config = SyncConfiguration.Builder(user, setOf(Toad::class))
.initialSubscriptions { realm ->
add(
realm.query<Toad>(
"name == $0",
"name value"
),
"subscription name"
)
}
.build()
val realm = Realm.open(config)
// wait for synchronization to complete before editing subscriptions
realm.subscriptions.waitForSynchronization(Duration.parse("10s"))
// remove all subscriptions to type Toad
realm.subscriptions.update {
this.removeAll(Toad::class)
}

To remove all subscriptions from the subscription set, use MutableSubscriptionSet.removeAll(). with no arguments:

Warning

If you remove all subscriptions and do not add a new one, you'll get an error. A realm opened with a flexible sync configuration needs at least one subscription to sync with the server.

// create an initial subscription named "subscription name"
val config = SyncConfiguration.Builder(user, setOf(Toad::class))
.initialSubscriptions { realm ->
add(
realm.query<Toad>(
"name == $0",
"name value"
),
"subscription name"
)
}
.build()
val realm = Realm.open(config)
// remove all subscriptions
realm.subscriptions.update {
this.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 - Kotlin SDKHandle Sync Errors - Kotlin SDK →
Share Feedback
© 2023 MongoDB, Inc.

About

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