Atlas Device Sync con Flexible Sync utiliza suscripciones y permisos para determinar qué datos sincronizar entre Atlas y su aplicación.
Puede agregar, actualizar y eliminar suscripciones de consultas para determinar qué datos se sincronizan con el dispositivo cliente.
Requisitos previos
Nota
Requisitos previos de sincronización flexible
Para habilitar la sincronización flexible en su aplicación, se requiere un clúster Atlas no fragmentado en ejecución MongoDB 5.0 o superior
Para usar Flexible Sync en una aplicación Flutter:
Alinear suscripciones con la aplicación backend
Las consultas de suscripción del lado del cliente deben estar alineadas con la configuración de sincronización del dispositivo en su aplicación de servicios de aplicaciones de backend.
Sus consultas de suscripción pueden:
Consulta todos los objetos de un tipo. Crea la consulta con Realm.all().
Consulta objetos que coincidan con los campos consultables de la aplicación backend. Crea la consulta con Realm.query() y una consulta del lenguaje de consulta de Realm que incluya uno o más campos consultables. El SDK de Realm genera un error si intentas crear una suscripción con campos no consultables.
Para obtener más información sobre cómo configurar campos consultables, consulte Campos consultables en la documentación de App Services.
Para obtener más información sobre las limitaciones del uso del lenguaje de consulta Realm con Flexible Sync, consulte la sección Limitaciones de RQL de Flexible Sync.
Suscribirse a Consultas
Novedad en la versión1.6.0 v.
Flutter v1.6.0 agrega APIs experimentales que se suscriben y se desuscriben de los resultados de una query. Estas API abstraen los detalles de añadir y remover suscripciones manualmente.
Para todas las suscripciones, necesitas un usuario autenticado y un reino sincronizado.
Si necesita más control sobre las suscripciones por motivos de optimización del rendimiento o de lógica empresarial, puede administrar manualmente el conjunto de suscripciones mediante subscriptions API. Consulte la sección "Consideraciones de rendimiento" en esta página para obtener más información.
Suscribirse a una consulta
Puedes suscribirte al RealmResults de una consulta mediante el método subscribe(). Al llamarlo, el SDK crea la nueva suscripción y la añade MutableSubscriptionSet al, de forma similar a la creación manual de una suscripción.
Opcionalmente, puede pasar un nombre de suscripción único para la consulta. Si agrega una suscripción con el mismo nombre que una suscripción existente, el SDK la sobrescribirá.
Si no se especifica un nombre de suscripción, este se establece en null y el identificador de la suscripción se basa en la cadena de consulta. Esto significa que cada vez que cambia la cadena de consulta, subscribe() crea una nueva suscripción.
Para suscribirse a una consulta, pase los siguientes argumentos a subscribe():
RealmResults query: Obligatorio. UnRealmResultsobjeto que puede crearse mediante el lenguaje de consulta Realm.String name: Opcional. Nombre de la suscripción al que puedes referenciar.bool update: Opcional. Si es verdadero, al agregar una suscripción con un nombre existente, se reemplaza la consulta existente por la nueva. Si es falso, el SDK genera una excepción para suscripciones duplicadas. Úselo solo con suscripciones con nombre.
En el siguiente ejemplo, nos suscribimos a dos nuevas consultas con nombre.
final boatQuery = realm.all<Boat>(); final bigPlaneQuery = realm.query<Plane>("numSeats > 100"); final boatSubscription = await boatQuery.subscribe(name: "boats"); final planeSubscription = await bigPlaneQuery.subscribe(name: "big-planes");
Tip
Especifique un nombre de suscripción
Le recomendamos que siempre especifique un nombre de suscripción, especialmente si su aplicación utiliza varias. Esto facilita la búsqueda y la gestión de sus suscripciones.
Espere a que se sincronice una suscripción de consulta
Al suscribirse a los resultados de una consulta, estos no contienen objetos hasta que se descargan los datos sincronizados. Si necesita esperar a que se descarguen los objetos sincronizados, configure la opción waitForSyncMode.
Este ejemplo utiliza la opción firstTime, que es el comportamiento predeterminado. Una suscripción con el comportamiento firstTime solo espera a que finalice la sincronización al crearse la suscripción.
final bigPlaneQuery = realm.query<Plane>("numSeats > 100"); final planeSubscription = await bigPlaneQuery.subscribe( name: "firstTimeSync", waitForSyncMode: WaitForSyncMode.firstTime, );
Las otras opciones admitidas waitForSyncMode son:
always: Espera a que se descarguen los objetos coincidentes cada vez que se inicia la aplicación. La aplicación debe tener conexión a internet cada vez que se inicia.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 en caché.
Opcionalmente, puedes especificar un token de cancelación para limitar cuánto tiempo sigue ejecutar la sincronizar descargar:
final bigPlaneQuery = realm.query<Plane>("numSeats > 200"); final planeSubscription = await bigPlaneQuery.subscribe( name: "alwaysWaitSync", waitForSyncMode: WaitForSyncMode.always, cancellationToken: TimeoutCancellationToken(Duration(seconds: 5)), );
Darse de baja de una consulta
Las suscripciones persisten entre sesiones de usuario a menos que las canceles. Puedes cancelar la suscripción a los resultados de una consulta mediante unsubscribe().
Esto elimina la suscripción de la lista de suscripciones activas, de forma similar a eliminarla manualmente. Tenga en cuenta que la lista de resultados puede seguir conteniendo objetos después de llamar unsubscribe() a si existe otra suscripción con objetos superpuestos.
Al llamar a unsubscribe() en una consulta, el SDK elimina cualquier suscripción con consultas que coincidan exactamente con la consulta en la que se llama a unsubscribe(). Este método retorna antes de que se eliminen del dominio los objetos que coinciden con la suscripción eliminada. La sincronización continúa en segundo plano según el nuevo conjunto de suscripciones.
planeQuery.unsubscribe(); trainQuery.unsubscribe();
Gestionar suscripciones manualmente
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, se utiliza la propiedad Realm.subscriptions para administrar un conjunto de suscripciones a consultas específicas en campos consultables.
Puedes hacer lo siguiente con tus suscripciones:
Obtenga una lista de todas las suscripciones
Añadir suscripciones
Comprobar el estado de la suscripción
Actualizar una suscripción con una nueva query
Eliminar suscripciones
Cuando los datos coinciden con la suscripción y el usuario autenticado tiene los permisos adecuados, Device Sync sincroniza los datos del backend con la app del cliente.
Los conjuntos de suscripciones persisten entre sesiones, incluso si ya no se incluye la suscripción en el código. La información de la suscripción se almacena en el archivo de base de datos del dominio sincronizado. Debe eliminar explícitamente una suscripción para que deje de intentar sincronizar los datos coincidentes.
Puede especificar un nombre de cadena para su suscripción. Si no le asigna un nombre, este se establece en null.
Al crear una suscripción, Realm busca datos que coincidan con una consulta sobre un tipo de objeto específico. En sus suscripciones de Sincronización Flexible, puede tener suscripciones sobre varios tipos de objeto diferentes o varias consultas sobre el mismo tipo de objeto.
Obtener suscripciones
Al utilizar Flexible Sync, puede acceder a un SubscriptionSet, una colección de suscripciones, a través de la Realm.subscriptions propiedad.
Puede utilizar este conjunto de suscripciones para agregar consultas a esta lista de suscripciones y actualizar las suscripciones existentes, como se muestra en los ejemplos a continuación.
final subscriptions = realm.subscriptions;
Agregar una consulta al conjunto de suscripciones
Debe realizar todas las mutaciones en las suscripciones establecidas dentro de un bloque de actualización. Para crear un bloque de actualización, llame a SubscriptionSet.update().
La función de devolución de llamada del bloque de actualización incluye un objeto MutableSubscriptionSet() como argumento. Puede modificar su método en SubscriptionSet para agregar una consulta a la suscripción.
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.
El método MutableSubscriptionSet.add() toma tres argumentos:
RealmResults query: Obligatorio. UnRealmResultsobjeto que puede crearse mediante la consulta del lenguaje de consulta Realm.String name: Opcional. Nombre de la suscripción al que puedes referenciar.bool update: Opcional. Si es verdadero, al agregar una suscripción con un nombre existente, se reemplaza la consulta existente por la nueva. Úselo solo con suscripciones con nombre.
Nota
Suscripciones duplicadas
Puede agregar una sola consulta o agrupar varias consultas dentro de un bloque SubscriptionSet.update. Actualizar las consultas es una operación costosa para el servidor. Le recomendamos encarecidamente que diseñe su aplicación para minimizar las actualizaciones de suscripciones. Puede lograrlo creando todas las suscripciones en un único bloque de actualización la primera vez que el usuario inicia la aplicación y agrupando los cambios posteriores en el conjunto de suscripciones.
En el siguiente ejemplo, nos suscribimos a dos consultas.
final planeQuery = realm.all<Plane>(); final longTrainQuery = realm.query<Train>("numCars >= 5"); realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.add(planeQuery, name: "planes"); mutableSubscriptions.add(longTrainQuery, name: 'long-trains', update: true); }); await realm.subscriptions.waitForSynchronization();
Actualizar suscripciones con una nueva consulta
Puede actualizar una suscripción con nombre con una nueva consulta. Para actualizar la consulta de una suscripción, abra un bloque de actualización con SubscriptionSet.update(). En la función de devolución de llamada del bloque de actualización, pase los siguientes argumentos a MutableSubscriptionSet.add():
La nueva consulta
El nombre de la suscripción que desea actualizar
update: true
No se puede actualizar una suscripción sin nombre. También se puede eliminar la suscripción sin nombre y crear una nueva con la consulta deseada.
En el siguiente ejemplo, los trenes largos se redefinen como cualquier tren que tenga más de 10 vagones.
final longerTrainQuery = realm.query<Train>("numCars > 10"); realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.add(longerTrainQuery, name: 'long-trains', update: true); });
Eliminar suscripciones
Para eliminar suscripciones del conjunto de suscripciones, puede:
Eliminar una sola suscripción con la consulta indicada
Eliminar una sola suscripción con el nombre especificado
Eliminar una sola suscripción con la referencia de suscripción
Eliminar todas las suscripciones para un tipo de objeto Realm
Eliminar todas las suscripciones
Cuando elimina una consulta de suscripción, el servidor también elimina los datos sincronizados del dispositivo cliente.
Eliminar una suscripción mediante consulta
Dentro de un bloque de actualización, puede eliminar una suscripción específica mediante una consulta. Abra un bloque de actualización con.SubscriptionSet.update() Pase el Subscription a MutableSubscriptionSet.removeByQuery().
En el siguiente ejemplo, se elimina la suscripción para todos los objetos Plane.
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByQuery(realm.all<Plane>()); });
Eliminar una suscripción por nombre
Dentro de un bloque de actualización, puedes eliminar una suscripción específica por nombre. Pasa el nombre a MutableSubscriptionSet.removeByName().
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByName('long-trains'); });
Eliminar una suscripción por referencia
Puedes eliminar una suscripción si tienes una referencia a su objeto Subscription. Dentro de un bloque de actualización de suscripción, pasa la Subscription referencia a MutableSubscriptionSet.remove().
final sub = realm.subscriptions[0]; realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.remove(sub); });
Eliminar todas las suscripciones para un tipo de objeto
Puedes eliminar todas las suscripciones de un tipo de objeto Realm determinado. Dentro de un bloque de actualización de suscripción, llama a MutableSubscriptionSet.removeByType().
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByType<Train>(); });
Eliminar todas las suscripciones
Dentro de un bloque de actualización de suscripción, puede eliminar todas las suscripciones sin nombre del conjunto de suscripciones con MutableSubscriptionSet.clear().
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.clear(); });
Espere a que los cambios de suscripción se sincronicen
Modificar el conjunto de suscripciones dentro de un bloque de actualización es solo una parte del proceso de cambio de una suscripción. Tras el cambio de suscripción local, el dominio se sincroniza con el servidor para resolver cualquier actualización de datos debida al cambio de suscripción. Esto incluye añadir o eliminar datos del dominio sincronizado.
Utilice Realm.subscriptions.waitForSynchronization() para esperar a que el servidor confirme este conjunto de suscripciones. Si el servidor rechaza el cambio, se genera una excepción.
Puede ocurrir una excepción si:
Te suscribes a una consulta no compatible. Suscribirte a una consulta no compatible pausará la sincronización. Para reanudarla, elimina la consulta no compatible.
Está realizando una acción no válida, como agregar un objeto que no coincide con una suscripción. Esto activa un reinicio del cliente: se borran los datos del dominio y se crea una nueva copia sin ninguna suscripción en el conjunto.
await realm.subscriptions.waitForSynchronization();
Estado de suscripción
Utilice la propiedad Realm.subscriptions.state para leer el estado actual del conjunto de suscripciones.
El superseded estado es un SubscriptionSetState que puede ocurrir cuando otro subproceso actualiza una suscripción en una instancia diferente del conjunto de suscripciones. Si el estado cambia superseded a, debe obtener una nueva instancia del conjunto de suscripciones para poder actualizarlo.
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.
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.