Docs Menu
Docs Home
/ /
Sincronizar datos del dispositivo

Administrar suscripciones de sincronización - SDK de Kotlin

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.

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.

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.

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:

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.

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.

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.

Debes tener al menos una suscripción antes de poder leer o guardar en el realm.

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 a RealmQuery o RealmResults. Esto añade automáticamente la suscripción al conjunto de suscripciones.

    • Agregue manualmente una suscripción al conjunto de suscripciones con la subscriptions API. 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.

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 {
@PrimaryKey
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 {
@PrimaryKey
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}")

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.

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.

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")

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.

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 valor timeout.

  • 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 valor timeout.

  • 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é.

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.

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.

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()

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.

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.

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"
)
}
}

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.

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")
}

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)
}

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()
}

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)
}

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 == o IN con una constante al menos una vez en la consulta de suscripción. Por ejemplo, user_id == $0, "641374b03725038381d2e1fb" o store_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 AND con el resto de la consulta. Por ejemplo, store_id IN {1,2,3} OR region=="Northeast" no es válido porque usa OR en lugar de AND. De igual manera, store_id == 1 AND active_promotions < 5 OR num_employees < 10 no es válido porque AND solo 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=="Northeast o truepredicate no son válidos porque no contienen dicho campo.

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

@avg, @count, @max, @min, @sum

Sufijos de consulta

DISTINCT, SORT, LIMIT

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.

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"

La sincronización flexible no admite consultas sobre propiedades en objetos incrustados ni enlaces. Por ejemplo, obj1.field == "foo".

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".

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").

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.

Volver

Configurar y abrir un reino sincronizado