Overview
Flexible Sync utiliza suscripciones y permisos para determinar qué datos sincronizar con tu aplicación.
Para usar Flexible Sync en el SDK:
Authenticate a user in your client project.
Abra el reino sincronizado con una configuración de sincronización flexible
You can add, update, and remove query subscriptions to determine which data syncs to the client device.
Tip
This page details how to manage subscriptions for Flexible Sync.
Para obtener información general sobre el uso de Atlas Device Sync con el SDK, como sincronizar cambios en segundo plano o pausar una sesión de sincronización, consulta Sincronizar cambios entre dispositivos.
For information about setting up permissions for Flexible Sync, check out Flexible Sync Rules & Permissions.
Suscríbete a campos consultables
Al configurar la sincronización flexible en el backend, se especifican los campos que la aplicación cliente puede consultar. En la aplicación cliente, utilice el
subscriptions API para gestionar un conjunto de suscripciones a consultas específicas en campos consultables. Puede crear consultas con la interfaz fluida del SDK de Java o con el lenguaje de consulta Realm.
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.
Puede:
Add subscriptions
React to subscription state
Actualiza las suscripciones con nuevas queries
Remover suscripciones individuales o todas las suscripciones de un tipo de objeto Realm.
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
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.
When you create a subscription, Realm 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.
You can create a subscription with an explicit name. Then, you can search for that subscription by name to update or remove it.
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { // add a subscription with a name subscriptions.add(Subscription.create("frogSubscription", realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); // later, you can look up this subscription by name Subscription subscription = realm.getSubscriptions().find("frogSubscription"); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> // add a subscription with a name subscriptions.add( Subscription.create( "frogSubscription", realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") // later, you can look up this subscription by name val subscription = realm.subscriptions.find("frogSubscription") } })
You can also search subscriptions by query. If you omit the name when creating a subscription, this is the only way to look up your subscription.
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { // add a subscription without assigning a name subscriptions.add(Subscription.create( realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); // later, you can look up this subscription by query Subscription subscription = realm.getSubscriptions().find(realm.where(Frog.class) .equalTo("species", "spring peeper")); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> // add a subscription without assigning a name subscriptions.add( Subscription.create( realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") // later, you can look up this subscription by query val subscription = realm.subscriptions.find( realm.where( Frog::class.java ).equalTo("species", "spring peeper") ) } })
Nota
Suscripciones duplicadas
Subscription names must be unique. Adding a subscription with the same name as an existing subscription throws an error.
If you do not explicitly name a subscription, and instead subscribe to the same unnamed query more than once, Realm does not persist duplicate queries to the subscription set.
Si te suscribes a la misma query más de una vez con diferentes nombres, Realm mantiene ambas suscripciones en el conjunto de suscripción.
Add a Subscription
Add a subscription in a subscriptions write block. You append each new subscription to the client's Realm subscriptions.
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { subscriptions.add(Subscription.create("subscriptionName", realm.where(Frog.class) .equalTo("species", "spring peeper"))); } }) .build(); // instantiate a realm instance with the flexible sync configuration Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> subscriptions.add( Subscription.create( "subscriptionName", realm.where(Frog::class.java) .equalTo("species", "spring peeper") ) ) } .build() // instantiate a realm instance with the flexible sync configuration Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") } })
Nota
Object Links
You must add both an object and its linked object to the subscription set to see a linked object.
Si los resultados de tu suscripción contienen un objeto con una propiedad que enlaza a un objeto no contenido en los resultados, el enlace parecerá ser nulo. No hay forma de distinguir si el valor de esa propiedad es legítimamente nulo, o si el objeto al que se enlaza existe pero está fuera del alcance de la suscripción de la consulta.
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. Use the waitForInitialRemoteData() builder method to force your application to block until client subscription data synchronizes to the backend before opening the realm:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions(new SyncConfiguration.InitialFlexibleSyncSubscriptions() { public void configure(Realm realm, MutableSubscriptionSet subscriptions) { subscriptions.add(Subscription.create("my subscription", realm.where(Frog.class) .equalTo("species", "poison dart"))); } }) .waitForInitialRemoteData(2112, TimeUnit.MILLISECONDS) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); } });
val config = SyncConfiguration.Builder(app.currentUser()) .initialSubscriptions { realm, subscriptions -> subscriptions.add( Subscription.create( "my subscription", realm.where(Frog::class.java) .equalTo("species", "poison dart") ) ) } .waitForInitialRemoteData( 2112, TimeUnit.MILLISECONDS ) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm.") } })
También puede usar SubscriptionSet.waitForSynchronization() o SubscriptionSet.waitForSynchronizationAsync() para retrasar la ejecución hasta que se complete la sincronización de suscripción tras instanciar una conexión de sincronización.
SubscriptionSet.State Enum
Additionally, you can watch the state of the subscription set with the SubscriptionSet.State enum. You can use subscription state to:
Show a progress indicator while data is downloading
Find out when a subscription set becomes superseded
You can access the state of your application's subscription set using SubscriptionSet.getState().
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.
Reemplazado
SUPERSEDED is a SubscriptionSet.State that can occur when another thread writes a subscription on a different instance of the subscription set. If the state becomes SUPERSEDED, you must obtain a new instance of the subscription set before you can write to it.
Update Subscriptions with a New Query
Puedes actualizar las suscripciones con SubscriptionSet.update(). En este ejemplo, usamos MutableSubscriptionSet.addOrUpdate() para actualizar la consulta de la suscripción llamada "my frog subscription":
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { // to update a named subscription, create a replacement with // the same name and add it to the subscription set subscriptions.addOrUpdate( Subscription.create("my frog subscription", realm.where(Frog.class) .equalTo("name", "Benedict Cumberburger"))); } });
realm.subscriptions.update { subscriptions -> // to update a named subscription, create a replacement with // the same name and add it to the subscription set subscriptions.addOrUpdate( Subscription.create( "my frog subscription", realm.where(Frog::class.java) .equalTo( "name", "Benedict Cumberburger" ) ) ) }
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:
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { // to update an unnamed subscription, remove it from the // subscription set, then add your new query to the set Subscription mySubscription = subscriptions.find(realm.where(Frog.class) .equalTo("species", "cane toad")); subscriptions.remove(mySubscription); subscriptions.addOrUpdate( Subscription.create( realm.where(Frog.class) .equalTo("species", "albino cane toad"))); } });
realm.subscriptions.update { subscriptions -> // to update an unnamed subscription, remove it from the // subscription set, then add your new query to the set val mySubscription = subscriptions.find( realm.where( Frog::class.java ).equalTo( "species", "cane toad" ) ) subscriptions.remove(mySubscription) subscriptions.addOrUpdate( Subscription.create( realm.where(Frog::class.java) .equalTo( "species", "albino cane toad" ) ) ) }
Eliminar suscripciones
To remove subscriptions, you can:
Remove a single subscription query
Remove all subscriptions to a specific object type
Remove all subscriptions
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.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { Subscription mySubscription = subscriptions.find("mySubscription"); subscriptions.remove(mySubscription); } });
realm.subscriptions.update { subscriptions -> val mySubscription = subscriptions.find("mySubscription") subscriptions.remove(mySubscription) }
Eliminar todas las suscripciones a un tipo de objeto Realm
Si desea eliminar todas las suscripciones a un tipo de objeto Realm específico, pase una clase al método removeAll():
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { subscriptions.removeAll(Frog.class); } });
realm.subscriptions.update { subscriptions -> subscriptions.removeAll( Frog::class.java ) }
Remove All Subscriptions
To remove all subscriptions from the subscription set, use removeAll() with no arguments:
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.
realm.getSubscriptions().update(new SubscriptionSet.UpdateCallback() { public void update(MutableSubscriptionSet subscriptions) { subscriptions.removeAll(); } });
realm.subscriptions.update { subscriptions -> subscriptions.removeAll() }
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.