Utiliza suscripciones y permisos para determinar qué datos sincronizar con tu aplicación. Esta página detalla cómo administrar las suscripciones para 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.
Para ello, complete los pasos descritos en el procedimiento Agregar sincronización de dispositivo a su aplicación.
Descripción general de las suscripciones
Cuando configura Flexible Sync en el backend, especifica qué campos puede consultar su aplicación cliente mediante suscripciones.
Cada suscripción corresponde a una consulta sobre campos consultables para un tipo de objeto específico.Consulte Campos consultables en la documentación de App Services para obtener más información.
Para cada suscripción de consulta, Realm busca datos que coincidan con la consulta. Los datos que coinciden con la suscripción, donde el usuario tiene los permisos adecuados, se sincronizan entre los clientes y la aplicación backend.
Puede construir consultas con el lenguaje de consulta Realm.
Importante
Flexible Sync no admite todos los operadores disponibles en el lenguaje de consulta Realm. Consulte las limitaciones de Flexible Sync RQL para obtener más información.
Suscribirse a tipos de objetos
Los conjuntos de suscripciones se basan en el tipo de objeto. Es posible que tenga varias suscripciones si tiene varios tipos de objetos de Realm. También puede tener varias suscripciones para el mismo tipo de objeto.
Sin embargo, si utiliza objetos vinculados, objetos asimétricos o datos geoespaciales en su aplicación, consulte las siguientes secciones para obtener información adicional:
Objetos vinculados
Si su aplicación utiliza objetos vinculados,debe agregar tanto el objeto en sí como su objeto vinculado al conjunto de suscripciones para ver el objeto vinculado real.
Cuando los resultados de su suscripción contienen un objeto con una propiedad que enlaza a un objeto no incluido en los resultados, el enlace aparece como nulo. No hay forma de distinguir si el valor de esa propiedad es nulo o si el objeto al que enlaza existe, pero no está visible para la suscripción de consulta.
Objetos asimétricos
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
Cambiado en la 1.13.0 versión: Datos geoespaciales compatibles con 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.
Para obtener más información, consulte Consulta de datos geoespaciales.
Suscripciones iniciales
Debes tener al menos una suscripción antes de poder leer o guardar en el realm.
Administrar suscripciones en su aplicación cliente
En la aplicación cliente, se agregan, actualizan y eliminan suscripciones a consultas específicas en los campos consultables. Esto determina qué datos se sincronizan con el dispositivo cliente.
Puede:
Agregue suscripciones con un nombre de suscripción opcional:
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.Agregue manualmente una suscripción al conjunto de suscripciones con la
subscriptionsAPI. Use esta API si necesita más control sobre las suscripciones para optimizar el rendimiento o mejorar la lógica de negocio. Consulte la sección "Consideraciones de rendimiento" para obtener más información.
Reaccionar al estado de la suscripción
Actualizar suscripciones con nuevas consultas
Remover suscripciones individuales o todas las suscripciones de un tipo de objeto Realm.
Acerca de los ejemplos de esta página
Los ejemplos de 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}")
Suscribirse a Consultas
Nuevo 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 consulta 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.
Suscribirse a una consulta
Puede agregar .subscribe() a una consulta para crear una suscripción para objetos que coincidan con una consulta específica:
// 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.
Para agregar un nombre a la suscripción, pase una cadena cuando llame a .subscribe():
// Add a subscription named "team_developer_education" val results = realm.query<Team>("teamName == $0", "Developer Education") .subscribe("team_developer_education")
Actualizar una suscripción de consulta
Puede actualizar una suscripción de consulta con nombre con una nueva consulta configurando updateExisting en 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 usted actualice manualmente la suscripción en el conjunto de suscripciones.
Espere a que se sincronice una suscripción de consulta
Al suscribirse al conjunto de resultados de una consulta, este no contiene objetos hasta que se sincroniza. Si su aplicación crea objetos, es posible que no necesite descargar los datos sincronizados antes de que el usuario pueda trabajar con ellos. Sin embargo, si su aplicación requiere datos del servidor para que el usuario pueda trabajar con ellos, puede especificar que la aplicación espere a que se sincronicen. Esto bloquea la ejecución de la aplicación hasta que se sincronicen los datos desde el servidor.
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: (Predeterminado) Esperar a descargar los objetos coincidentes cuando la aplicación crea la suscripción inicialmente. De lo contrario, regresar sin esperar nuevas descargas. La aplicación debe tener conexión a internet para descargar los datos al agregar la suscripción inicialmente. Opcionalmente, puede especificar un valortimeout.ALWAYS: Esperar a que se descarguen los objetos coincidentes cada vez que se llama al método.subscribe(). La aplicación debe tener conexión a internet para descargar los datos. Opcionalmente, se puede especificar un valortimeout.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é.
Gestionar suscripciones manualmente
En la aplicación cliente, use la API subscriptions para administrar manualmente un conjunto de suscripciones. Con esta API, puede agregar, actualizar o eliminar consultas específicas en campos consultables. Estas consultas determinan qué datos se sincronizan con el dispositivo cliente.
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.
Añadir una suscripción
Puede agregar una suscripción sin nombre o una suscripción con nombre.
Tip
Especifique un nombre de suscripción
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.
Para crear una suscripción manualmente, agréguela a un bloque de actualización de suscripciones. Cada nueva suscripción se agrega a las suscripciones de Realm del cliente.
realm.subscriptions.update { add( realm.query<Task>("progressMinutes >= $0",60) ) }
También puede especificar un nombre de suscripción al crear la suscripción:
// Add a subscription named "team_dev_ed" realm.subscriptions.update { realm -> add( realm.query<Team>("teamName == $0", "Developer Education"), name = "team_dev_ed" ) }
Importante
Enlaces de objetos
Debe agregar un objeto y su objeto vinculado al conjunto de suscripciones para ver un objeto vinculado.
Si los resultados de su suscripción contienen un objeto con una propiedad que enlaza a un objeto no incluido en los resultados, el enlace aparecerá como nulo. No hay forma de distinguir si el valor de esa propiedad es nulo o si el objeto al que enlaza existe, pero no está disponible para el cliente debido a la falta de suscripciones.
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.
Pase el parámetro initialSubscriptions con las consultas de suscripción que desea utilizar para iniciar el reino:
// 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()
Si su aplicación necesita volver a ejecutar esta suscripción inicial cada vez que se inicia, puede pasar un parámetro adicional: rerunOnOpen. Este valor booleano indica si la suscripción inicial debe volver a ejecutarse cada vez que se inicia la aplicación. Podría ser necesario para volver a ejecutar intervalos de tiempo dinámicos u otras consultas que requieran volver a calcular las variables estáticas de la suscripción.
En este ejemplo, solo queremos tareas incompletas. Con rerunOnOpen establecido en true, la consulta recalcula dinámicamente los objetos relevantes para sincronizar según los resultados deseados cada vez que se inicia la aplicación:
// `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
Escribir una actualización en el conjunto de suscripciones localmente es solo un componente del cambio de una suscripción. Tras el cambio de suscripción local, el cliente se sincroniza con el servidor para resolver cualquier actualización de datos debida al cambio de suscripción. Esto podría implicar añadir o eliminar datos del dominio sincronizado.
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"))
También puede utilizar SubscriptionSet.waitForSynchronization() para retrasar la ejecución hasta que se complete la sincronización de la suscripción después de crear una conexión de sincronización.
Estado del conjunto de suscripción
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 "Completado"
El estado "Completado" del conjunto de suscripción no significa que la sincronización esté completa ni que todos los documentos se hayan sincronizado. "Completado" significa que han ocurrido las dos cosas siguientes:
La suscripción se ha convertido en el conjunto de suscripciones activas que actualmente se está sincronizando con el servidor.
Los documentos que coincidían con la suscripción en el momento de enviarla al servidor se encuentran ahora en el dispositivo local. Tenga en cuenta que esto no incluye necesariamente todos los documentos que coinciden actualmente con la suscripción.
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.
Actualizar suscripciones con una nueva consulta
Puede actualizar las suscripciones utilizando SubscriptionSet.update().
En este ejemplo, usamos MutableSubscriptionSet.add() para actualizar la consulta de la "bob_smith_teams" suscripción. Debe establecer el updateExisting parámetro en para true actualizar una suscripción add() con:
// 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 ) }
No se pueden actualizar las suscripciones creadas sin nombre. Sin embargo, se pueden buscar suscripciones sin nombre por su consulta, eliminarlas del conjunto de suscripciones y luego agregar una nueva suscripción con una consulta actualizada:
// 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
Para eliminar suscripciones, puedes:
Eliminar una sola consulta de suscripción
Eliminar todas las suscripciones a un tipo de objeto específico
Eliminar todas las suscripciones
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.
Eliminar una sola suscripción
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) }
Eliminar todas las suscripciones
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() }
Eliminar todas las suscripciones sin nombre
Nuevo 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.
Puede eliminar todas las suscripciones sin nombre (anónimas) del conjunto de suscripciones configurando anonymousOnly en true cuando llame al método removeAll:
// Remove all unnamed (anonymous) subscriptions realm.subscriptions.update { removeAll(anonymousOnly = true) }
Requisitos y limitaciones de RQL de sincronización flexible
Requisitos de suscripción a campos consultables indexados
Añadir un campo consultable indexado a tu aplicación puede mejorar el rendimiento de consultas simples sobre datos con particiones estrictas. Por ejemplo, una aplicación donde las consultas asignan datos de forma estricta a un dispositivo, tienda o usuario,user_id == $0, “641374b03725038381d2e1fb” como, es una buena candidata para un campo consultable indexado. Sin embargo, un campo consultable indexado tiene requisitos específicos para su uso en una suscripción de consultas:
El campo consultable indexado debe usarse en todas las consultas de suscripción. No puede faltar en la consulta.
El campo consultable indexado debe usar una comparación
==oINcon una constante al menos una vez en la consulta de suscripción. Por ejemplo,user_id == $0, "641374b03725038381d2e1fb"ostore_id IN $0, {1,2,3}.
Opcionalmente, puede incluir una comparación AND siempre que el campo consultable indexado 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).
Las consultas de sincronización flexibleno válidas en un campo consultable indexado incluyen consultas donde:
El campo consultable indexado no usa
ANDcon el resto de la consulta. Por ejemplo,store_id IN {1,2,3} OR region=="Northeast"no es válido porque usaORen lugar deAND. De igual manera,store_id == 1 AND active_promotions < 5 OR num_employees < 10no es válido porqueANDsolo se aplica al término contiguo, no a toda la consulta.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.A la consulta le falta por completo el campo consultable indexado. Por ejemplo,
region=="Northeastotruepredicateno son válidos porque no contienen dicho campo.
Operadores de consulta no admitidos en Flexible Sync
La sincronización flexible presenta algunas limitaciones al usar operadores RQL. Al escribir la suscripción de consulta que determina qué datos sincronizar, el servidor no admite estos operadores. Sin embargo, aún puede usar todas las funciones de RQL para consultar el conjunto de datos sincronizados en la aplicación cliente.
Tipo de operador | Operadores no compatibles |
|---|---|
Operadores agregados |
|
Sufijos de consulta |
|
Las consultas que no distinguen entre mayúsculas y minúsculas ([c]) no pueden usar índices eficazmente. Por lo tanto, no se recomiendan, ya que podrían causar problemas de rendimiento.
Flexible Sync solo admite @count para campos de matriz.
Consultas de lista
Flexible Sync admite la consulta de listas mediante 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 }"
Si un campo consultable tiene un valor de matriz, puedes consultar para ver si contiene un valor constante:
// Query an array-valued queryable field for a constant value "'comedy' IN genres"
Advertencia
No se pueden comparar dos listas en una consulta de sincronización flexible. Tenga en cuenta que esta sintaxis del lenguaje de consulta de dominio es válida fuera de las consultas de sincronización flexible.
// 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
La sincronización flexible no admite consultas sobre propiedades en objetos incrustados ni enlaces. Por ejemplo, obj1.field == "foo".
Límite de tamaño de consulta
El límite de tamaño para cualquier suscripción de consulta en su conjunto de suscripciones es de kB. Superar este límite genera 256 un error "LimitsExceeded".
Consideraciones sobre el rendimiento
Eficiencia de la API
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 grupo para un mejor rendimiento
Cada transacción de escritura para un conjunto de suscripciones tiene un coste de rendimiento. Si necesita realizar varias actualizaciones a un objeto de Realm durante una sesión, considere mantener los objetos editados en memoria hasta que se completen todos los cambios. Esto mejora el rendimiento de la sincronización al escribir solo el objeto completo y actualizado en su reino, en lugar de cada cambio.