uses subscriptions and permissions to determine which data to sync with your App. This page details how to manage subscriptions for Flexible Sync.
Para obtener más información, consulte Sincronización flexible en la documentación de App Services.
Requisitos previos
Antes de que puedas trabajar con las suscripciones de Flexible Sync, debes configurar tu aplicación para utilizar Device Sync y configurar Flexible Sync en el backend.
To do this, complete the steps outlined in the Add Device Sync to Your App procedure.
Subscriptions Overview
Cuando configuras la sincronización flexible en el backend, especificas qué campos puede consultar tu aplicación cliente usando suscripciones.
Each subscription corresponds to a query on queryable fields for a specific object type. See Queryable Fields in the App Services documentation for more information.
For each query subscription, Realm looks for data matching the query. Data matching the subscription, where the user has the appropriate permissions, syncs between clients and the backend application.
Puedes construir consultas con Realm Query Language.
Importante
Flexible Sync no es compatible con todos los operadores disponibles en Realm Query Language. Consulta Limitaciones de RQL en Flexible Sync para obtener detalles.
Subscribe to Object Types
Subscription sets are based on object type. You might have multiple subscriptions if you have many types of Realm objects. You can also have multiple subscriptions on the same object type.
However, if you use linked objects, asymmetric objects, or geospatial data in your app, refer the following sections for additional information:
Linked Objects
Si tu aplicación usa objetos vinculados, debes agregar tanto el objeto en sí como su objeto vinculado al conjunto de suscripción para ver el objeto vinculado real.
When 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 null or whether the object it links to exists but is out of view of the query subscription.
Asymmetric Objects
Si tu aplicación utiliza Data Ingest para sincronizar objetos asimétricos de forma unidireccional, no podrás crear suscripciones para esos objetos. Si tu aplicación contiene objetos asimétricos y no asimétricos en el mismo realm, puedes añadir queries de suscripción de Flexible Sync para los objetos no asimétricos.
Datos geoespaciales
Changed in version 1.13.0: Geospatial data supported in Atlas Device Sync
En la versión 1.13.0 y posteriores del SDK de Kotlin, se pueden crear suscripciones a consultas geoespaciales. Si se intenta suscribirse a una consulta geoespacial con una versión anterior del SDK, se recibirá un error de servidor con una escritura compensatoria.
For more information, refer to Query Geospatial Data.
Initial Subscriptions
Debes tener al menos una suscripción antes de poder leer o guardar en el realm.
Administrar suscripciones en su aplicación cliente
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.
Puede:
Add subscriptions with an optional subscription name:
En la versión 1.10.0 y posteriores del SDK de Kotlin, puedes usar
.subscribe()Suscribirse aRealmQueryoRealmResults. Esto añade automáticamente la suscripción al conjunto de suscripciones.Manually add a subscription to the subscription set with the
subscriptionsAPI. Use this API if you need more control over subscriptions for performance optimization or business logic reasons. See the Performance Considerations section for more information.
React to subscription state
Actualiza las suscripciones con nuevas queries
Remover suscripciones individuales o todas las suscripciones de un tipo de objeto Realm.
About the Examples on This Page
Los ejemplos en esta página utilizan un conjunto de datos para una aplicación de lista de tareas.
Los dos tipos de objetos de Realm son Team y Task:
class Task : RealmObject { var _id: ObjectId = ObjectId() var taskName: String = "" var assignee: String? = null var completed: Boolean = false var progressMinutes: Int = 0 var dueDate: RealmInstant? = null } class Team : RealmObject { var _id: ObjectId = ObjectId() var teamName: String = "" var tasks: RealmList<Task>? = realmListOf() var members: RealmList<String> = realmListOf() }
Los ejemplos de esta página también suponen que tiene un usuario autorizado y una sincronización flexible SyncConfiguration():
// Login with authorized user and define a Flexible Sync SyncConfiguration val app = App.create(YOUR_APP_ID) val user = app.login(credentials) val flexSyncConfig = SyncConfiguration.Builder(user, setOf(Task::class, Team::class)) .initialSubscriptions { // Define the initial subscription set for the realm ... } .build() // Open the synced realm and manage subscriptions val realm = Realm.open(flexSyncConfig) Log.v("Successfully opened realm: ${realm.configuration}")
Subscribe to Queries
Novedades en la versión 1.10.0.
Para simplificar la gestión de suscripciones, la versión del SDK de Kotlin de Realm 1.10.0 añade la API experimental.subscribe() para suscribirse a un RealmQuery RealmResults conjunto o. Esta API simplifica la adición y eliminación manual de suscripciones mediante conjuntos de suscripciones.
Puede:
Suscribirse automáticamente a una query con un nombre opcional
Actualiza una suscripción nominal con una nueva query
Si necesita más control sobre las suscripciones para optimizar el rendimiento o la lógica de negocio, puede administrar manualmente el conjunto de suscripciones mediante la API. Consulte la subscriptions sección "Consideraciones de rendimiento" para obtener más información.
Subscribe to a Query
You can .subscribe() to a query to create a subscription for objects matching a specific query:
// Subscribe to a specific query val realmResults = realm.query<Task>("progressMinutes >= $0", 60) .subscribe() // Subscribe to all objects of a specific type val realmQuery = realm.query<Team>() realmQuery.subscribe()
Esto crea una suscripción sin nombre y la agrega MutableSubscriptionSet a, en lugar de requerir que agregue manualmente la suscripción al conjunto de suscripciones.
Suscríbete a una query con un nombre
Si tu aplicación funciona con varias suscripciones o quieres actualizar una, puedes añadir un nombre al suscribirte a una consulta. Posteriormente, puedes usar este nombre para actualizar la consulta de la suscripción o eliminarla por nombre.
To add a name to the subscription, pass a string when you call .subscribe():
// Add a subscription named "team_developer_education" val results = realm.query<Team>("teamName == $0", "Developer Education") .subscribe("team_developer_education")
Update a Query Subscription
You can update a named query subscription with a new query by setting updateExisting to true:
// Create a subscription named "bob_smith_teams" val results = realm.query<Team>("$0 IN members", "Bob Smith") .subscribe("bob_smith_teams") // Add another subscription with the same name with `updateExisting` set to true // to replace the existing subscription val updateResults = realm.query<Team>("$0 IN members AND teamName == $1", "Bob Smith", "QA") .subscribe("bob_smith_teams", updateExisting = true)
Esto actualiza la suscripción automáticamente, en lugar de requerir que se actualice manualmente la suscripción en el set de suscripción.
Wait for a Query Subscription to Sync
When you subscribe to a query's results set, that set does not contain objects until it syncs. 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 the server before the user can work with it, you can specify that the app should wait for data to sync. This blocks app execution until data syncs from the server.
val results = realm.query<Team>("$0 IN members", "Bob Smith") .subscribe("bob_smith_teams", updateExisting = false, WaitForSync.ALWAYS) // After waiting for sync, the results set contains all the objects // that match the query - in our case, 1 println("The number of teams that have Bob Smith as a member is ${results.size}")
Esta opción utiliza la enumeración WaitForSync, cuyos valores son:
FIRST_TIME: (por defecto) Esperar a descargar los objetos coincidentes cuando tu app cree inicialmente la suscripción. De lo contrario, retornar sin esperar nuevas descargas. La aplicación debe tener una conexión a Internet para descargar los datos cuando inicialmente agregues la suscripción. Opcionalmente se puede especificar un valor detimeout.ALWAYS: Wait to download matching objects every time the.subscribe()method is called. The app must have an internet connection to download the data. You can optionally specify atimeoutvalue.NEVERNo esperes para descargar los objetos coincidentes. La aplicación necesita conexión a internet para que el usuario se autentique la primera vez que se inicia, pero puede abrirse sin conexión en los siguientes inicios usando credenciales almacenadas en caché.
Manually Manage Subscriptions
In the client application, use the subscriptions API to manually manage a set of subscriptions. With this API, you can add, update, or remove specific queries on queryable fields. These queries determine which data syncs to the client device.
En la versión 1.10.0 y posteriores del SDK de Kotlin, se pueden agregar suscripciones automáticamente con la API.subscribe(). Esta API agrega suscripciones a un MutableSubscriptionSet directamente desde un RealmQuery o RealmResults un.
Add a Subscription
Puedes añadir una suscripción sin nombre o una suscripción con nombre.
Tip
Specify a Subscription Name
Especifique siempre un nombre de suscripción si su aplicación utiliza varias. Esto facilita la búsqueda, actualización y eliminación de suscripciones en otras partes de la aplicación.
To manually create a subscription, add the subscription in a subscriptions update block. You append each new subscription to the client's Realm subscriptions.
realm.subscriptions.update { add( realm.query<Task>("progressMinutes >= $0",60) ) }
You can also specify a subscription name when you create the subscription:
// Add a subscription named "team_dev_ed" realm.subscriptions.update { realm -> add( realm.query<Team>("teamName == $0", "Developer Education"), name = "team_dev_ed" ) }
Importante
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 null or whether the object it links to exists but is not available to the client due to missing subscriptions.
Arranque el reino con suscripciones iniciales
Debe tener al menos una suscripción para poder leer o escribir en el dominio. Puede iniciar un dominio con una suscripción inicial al abrirlo con SyncConfiguration(). Consulte "Abrir un dominio sincronizado" para obtener más información.
Pass the initialSubscriptions parameter with the subscription queries you want to use to bootstrap the realm:
// Bootstrap the realm with an initial query to subscribe to val flexSyncConfig = SyncConfiguration.Builder(user, setOf(Team::class, Task::class)) .initialSubscriptions { realm -> add( realm.query<Team>("$0 IN members", "Bob Smith"), "bob_smith_teams" ) } .build()
If your app needs to rerun this initial subscription every time the app starts, you can pass an additional parameter: rerunOnOpen. This is a boolean that denotes whether the initial subscription should re-run every time the app starts. You might need to do this to re-run dynamic time ranges or other queries that require a re-computation of static variables for the subscription.
In this example, we only want incomplete tasks. With rerunOnOpen set to true, the query dynamically recalculates the relevant objects to sync based on the desired query results every time the app starts:
// `rerunOnOpen` lets the app recalculate this query every time the app opens val rerunOnOpenConfig = SyncConfiguration.Builder(user, setOf(Team::class, Task::class)) .initialSubscriptions(rerunOnOpen = true) { realm -> add( realm.query<Team>("completed == $0", false) ) } .build()
Espere a que los cambios de suscripción se sincronicen
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.
Utilice el método de construcción SyncConfiguration.waitForInitialRemoteData() para forzar que su aplicación se bloquee hasta que los datos de suscripción del cliente se sincronicen con el backend antes de abrir el reino:
// Update the list of subscriptions realm.subscriptions.update { add( realm.query<Team>("$0 IN members", "Jane Doe"), "jane_doe_teams" ) } // 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.
Subscription Set State
Utilice la propiedad SubscriptionSet.state para leer el estado actual del conjunto de suscripciones.
SUPERCEDED (sic -- nótese la ortografía alternativa) es un SubscriptionSetState que puede ocurrir cuando otro hilo escribe una suscripción en una instancia diferente del conjunto de suscripciones. Si el estado se convierte SUPERCEDED en, debe obtener una nueva instancia del conjunto de suscripciones antes de poder escribir en él.
Nota
Estado de suscripción 'Completo'
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.
El SDK de Realm no proporciona una manera de verificar si todos los documentos que coinciden con una suscripción se han sincronizado con el dispositivo.
Update Subscriptions with a New Query
Puede actualizar las suscripciones utilizando SubscriptionSet.update().
In this example, we use MutableSubscriptionSet.add(). to update the query for the subscription named "bob_smith_teams". You must set the updateExisting parameter to true to update a subscription with add():
// Create a subscription named "bob_smith_teams" realm.subscriptions.update { add( realm.query<Team>("$0 IN members", "Bob Smith"), "bob_smith_teams" ) } // Set `updateExisting` to true to replace the existing // "bob_smith_teams" subscription realm.subscriptions.update { add( realm.query<Team>("$0 IN members AND $1 IN members", "Bob Smith", "Jane Doe"), "bob_smith_teams", 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:
// Search for the subscription by query val subscription = realm.subscriptions.findByQuery( realm.query<Team>("teamName == $0", "Developer Education") ) // Remove the returned subscription and add the updated query if (subscription != null) { realm.subscriptions.update { remove(subscription) add( realm.query<Team>("teamName == $0", "DevEd"), "team_developer_education" ) } }
Eliminar suscripciones
To remove subscriptions, you can:
Remove a single subscription query
Remove all subscriptions to a specific object type
Remove all subscriptions
Remover todas las suscripciones sin nombre
Cuando elimina una consulta de suscripción, Realm elimina de forma asincrónica los datos sincronizados que coinciden con la consulta del dispositivo cliente.
Remove a Single Subscription
Puedes eliminar una consulta de suscripción específica usando MutableSubscriptionSet.remove(). Puedes buscar la suscripción por nombre y luego pasar la suscripción devuelta a remove(), o pasar el nombre de la suscripción directamente a remove():
realm.subscriptions.update { add( realm.query<Team>("$0 IN members", "Bob Smith"), "bob_smith_teams" ) } // Wait for synchronization to complete before updating subscriptions realm.subscriptions.waitForSynchronization(Duration.parse("10s")) // Remove subscription by name realm.subscriptions.update { remove("bob_smith_teams") }
Eliminar todas las suscripciones a un tipo de objeto Realm
Si desea eliminar todas las suscripciones a un tipo de objeto específico, pase una clase al método MutableSubscriptionSet.removeAll().:
realm.subscriptions.update { add( realm.query<Team>("$0 IN members", "Bob Smith"), "bob_smith_teams") } // Wait for synchronization to complete before updating subscriptions realm.subscriptions.waitForSynchronization(Duration.parse("10s")) // Remove all subscriptions to type Team realm.subscriptions.update { removeAll(Team::class) }
Remove All Subscriptions
Para eliminar todas las suscripciones del conjunto de suscripciones, utilice MutableSubscriptionSet.removeAll(). sin argumentos:
Advertencia
Si elimina todas las suscripciones y no agrega una nueva, obtendrá un error. Un realm abierto con una configuración de sincronización flexible necesita al menos una suscripción para sincronizar con el servidor.
// Remove all subscriptions realm.subscriptions.update { removeAll() }
Remover todas las suscripciones sin nombre
Novedades en la versión 1.10.0.
Es posible que desee eliminar las suscripciones sin nombre que son transitorias o generadas dinámicamente, pero dejar las suscripciones con nombre en su lugar.
You can remove all unnamed (anonymous) subscriptions from the subscription set by setting anonymousOnly to true when you call the removeAll method:
// Remove all unnamed (anonymous) subscriptions realm.subscriptions.update { removeAll(anonymousOnly = true) }
Requisitos y limitaciones de RQL de Flexible Sync
Requisitos de suscripción a campos consultables indexados
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
==orINcomparison against a constant at least once in the subscription query. (El campo consultable debe utilizar una comparación o contra una constante al menos una vez en la consulta de suscripción.) For example,user_id == $0, "641374b03725038381d2e1fb"orstore_id IN $0, {1,2,3}. (Por ejemplo, o .)
Opcionalmente, puedes incluir una comparación de AND siempre que el campo indexado consultable se compare directamente con una constante usando == o IN al menos una vez. Por ejemplo, store_id IN {1,2,3} AND region=="Northeast" o store_id == 1 AND (active_promotions < 5 OR num_employees < 10).
Invalid Flexible Sync queries on an indexed queryable field include queries where:
The indexed queryable field does not use
ANDwith the rest of the query. For examplestore_id IN {1,2,3} OR region=="Northeast"is invalid because it usesORinstead ofAND. Similarly,store_id == 1 AND active_promotions < 5 OR num_employees < 10is invalid because theANDonly applies to the term next to it, not the entire query.El campo consultable indexado no se utiliza en un operador de igualdad. Por ejemplo,
store_id > 2 AND region=="Northeast"no es válido porque solo utiliza el operador>con el campo consultable indexado y no tiene una comparación de igualdad.The query is missing the indexed queryable field entirely. For example,
region=="Northeastortruepredicateare invalid because they do not contain the indexed queryable field.
Unsupported Query Operators in Flexible Sync
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.
Tipo de operador | Operadores no compatibles |
|---|---|
Aggregate Operators |
|
Query Suffixes |
|
Las queries que no distinguen entre mayúsculas y minúsculas ([c]) no pueden usar índices de manera eficaz. Como resultado, no se recomiendan las queries que no distinguen entre mayúsculas y minúsculas, ya que podrían provocar problemas de rendimiento.
Flexible Sync only supports @count for array fields.
List Queries
Flexible Sync admite la consulta de listas usando el operador IN.
Puede consultar una lista de constantes para ver si contiene el valor de un campo consultable:
// 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"
Advertencia
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"
Objetos incrustados o vinculados
Flexible Sync does not support querying on properties in Embedded Objects or links. For example, obj1.field == "foo".
Query Size Limit
The size limit for any given query subscription in your subscription set is 256 kB. Exceeding this limit results in a LimitsExceeded Error.
Consideraciones sobre el rendimiento
API Efficiency
Administrar varias suscripciones con la .subscribe() API (descrita en la sección "Suscribirse a consultas") es menos eficiente que realizar actualizaciones por lotes cuando se administran manualmente mediante la API de conjuntos de suscripciones. Para un mejor rendimiento al realizar cambios en varias suscripciones, utilice la subscriptions.update API (descrita en la sección "Administrar suscripciones manualmente").
Actualizaciones de grupos para mejorar el rendimiento
Every write transaction for a subscription set has a performance cost. If you need to make multiple updates to a Realm 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 realm instead of every change.