Flexible Sync uses subscriptions and permissions to determine what data to sync with your App. You must have at least one subscription before you can read from or write to a realm with Flexible Sync enabled. This page details how to manage those subscriptions.
You can add, update, and remove query subscriptions to control what data syncs to the client device. In the Realm Node.js SDK v12.0.0 and later, you can subscribe to queries instead of or in addition to manually managing subscriptions.
No puedes crear suscripciones para Ingesta de datos y objetos asimétricos porque solo envían datos al backend de su aplicación.
Importante
Limitaciones de las consultas de Flexible Sync
Las suscripciones de sincronización flexible solo admiten un subconjunto de operadores de consulta RQL. Consulte la documentación sobre las limitaciones de RQL de sincronización flexible para obtener información sobre los operadores no compatibles.
Requisitos previos
You need to meet the following requirements before you can use Atlas Device Sync with the Node.js SDK:
Un clúster de Atlas no particionado ejecutando MongoDB 5.0 o superior.
Versión de JavaScript de Realm 10.12.0 o posterior.
In addition to the requirements, you need to set up the following to use Flexible Sync in a Node.js client:
Subscribe to Queries
New in version 12.0.0.
Realm Node.js v12.0.0 añade APIs experimentales que se suscriben y desuscriben de los resultados de una query. Estas API abstraen los detalles de añadir y remover suscripciones manualmente.
For all subscriptions, you need an authenticated user and a Flexible Sync realm.
Cambiado en la versión 12.3.0: Datos geoespaciales compatibles con Atlas Device Sync
In the Realm Node.js SDK v12.3.0 and later, you can create subscriptions to geospatial queries. If you try to subscribe to a geospatial query with an older version of the SDK, you will receive a server error with a compensating write.
For more information, refer to Query Geospatial Data.
Subscribe to a Query
We recommend that you name your subscriptions. This makes finding and managing your subscriptions easier. Subscription names must be unique. Trying to add a subscription with the same name as an existing subscription throws an error.
To subscribe to a query:
Query for the objects that you want to read and write.
Call
subscribe()en los resultados de la consulta para crear una suscripción de sincronización para los objetos que coincidan con la consulta.Pasa un objeto
SubscriptionOptionsque contiene la propiedadnameasubscribe().
const subOptions = { name: "All completed tasks", }; const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(subOptions); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe({ name: "All completed tasks" }); const completedTasksSubscription = realm.subscriptions.findByName( "All completed tasks" ); // ...work with the subscribed results list or modify the subscription
Subscribe to a Query without a Subscription Name
Most of the time, you should give your subscriptions a name. If you don't, the name is set to null.
Si usa filtered() en una suscripción de consulta sin nombre, el identificador de la suscripción se basa en la consulta filtered. Esto significa que cada vez que cambie la cadena de consulta, subscribe() creará una nueva suscripción.
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, }, }; const realm = await Realm.open(config); const completedTasks = await realm .objects(Task) .filtered('status == "completed"') .subscribe(); // ...work with the subscribed results list
Wait for a Query Subscription to Sync
When you subscribe to a query's results, the results do not contain objects until synced data is downloaded. When you do need to wait for syned objects to finish downloading, use waitForSync. You can specify different behavior for your subscriptions and how they handle witing for downloads.
Este ejemplo utiliza la opción FirstTime, que es el comportamiento por defecto. Una suscripción con el comportamiento FirstTime solo espera que la sincronización termine cuando se crea por primera vez una suscripción.
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", });
The other supported WaitForSync options are:
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.Never: Never wait to download matching objects. The app needs an internet connection for the user to authenticate the first time the app launches, but can open offline on subsequent launches using cached credentials.
Opcionalmente puedes especificar un valor timeout para limitar cuánto tiempo dura la descarga de la sincronización:
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Add subscription with timeout // If timeout expires before sync is completed, currently-downloaded // objects are returned and sync download continues in the background. const taskSubscription = await completedTasks.subscribe({ behavior: WaitForSync.Always, timeout: 500, });
Darse de baja de una consulta
Para cancelar la suscripción a los resultados de una query utilizando unsubscribe():
import { WaitForSync } from "realm"; // Get tasks that have a status of "in progress". const completedTasks = realm .objects(Task) .filtered("status == 'completed'"); // Only waits for sync to finish on the initial sync. await completedTasks.subscribe({ behavior: WaitForSync.FirstTime, name: "First time sync only", }); // Unsubscribe completedTasks.unsubscribe();
Esto elimina la suscripción de la lista de suscripciones activas, de forma similar a eliminar una suscripción manualmente.
Una lista de resultados aún puede contener objetos después de llamar a unsubscribe() si existe otra suscripción que contiene objetos superpuestos.
Cuando llamas a unsubscribe(), se elimina la suscripción asociada. Las suscripciones se eliminan por nombre. Si no tienen un nombre, unsubscribe() remueve cualquier query que coincida exactamente con la que llamas en unsubscribe().
The unsubscribe() method returns before objects matching the removed subscription are deleted from the realm. Sync continues in the background based on the new set of subscriptions.
Manually Manage Subscriptions
Puede utilizar la API de suscripciones para administrar manualmente un conjunto de suscripciones a consultas específicas en campos consultables.
Puede:
Obtenga una lista de todas las suscripciones
Add subscriptions
Comprobar el estado de la suscripción
Actualiza las suscripciones con nuevas queries
Remover suscripciones individuales o todas las suscripciones de un tipo
Cuando los datos coinciden con la suscripción y tienen los permisos apropiados, se sincronizan entre los dispositivos y la aplicación backend.
When you create a subscription, Realm looks for data matching a query on a specific object type. You can have subscriptions on several different object types. You can also have multiple queries on the same object type.
Importante
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.
Get All Subscriptions
Al utilizar un reino sincronizado flexible, puede acceder SubscriptionSet a, una colección de suscripciones, a través de la propiedad realm.subscriptions.
// get the SubscriptionSet for the realm const subscriptions = realm.subscriptions;
Add a Subscription
Subscriptions are based on the results of realm queries.
In the following example, completed and progressMinutes have been set as queryable fields in an App Services App. In the client code, we create filtered queries and then subscribe to their results:
Completed tasks
Tareas completadas que han superado los 120
progressMinutes
const tasks = realm.objects("Task"); const longRunningTasks = tasks.filtered( 'status == "completed" && progressMinutes > 120' ); await realm.subscriptions.update((mutableSubs) => { mutableSubs.add(longRunningTasks, { name: "longRunningTasksSubscription", }); mutableSubs.add(realm.objects("Team"), { name: "teamsSubscription", }); });
Set Initial Subscriptions
You must have at least one subscription before you can read from or write to a Flexible Sync realm. You can add an initial subscription when opening a realm.
Para initialSubscriptions configurar las suscripciones iniciales, incluya el campo en la configuración de sincronización de su dominio. Dentro del initialSubscriptions objeto, agregue un update campo configurado para una devolución de llamada que se suscriba a las consultas:
const config = { schema: [Task], sync: { user: app.currentUser, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
const config: Realm.Configuration = { schema: [Task], sync: { user: app.currentUser!, flexible: true, initialSubscriptions: { update: (subs, realm) => { subs.add(realm.objects(Task).filtered("status == 'in progress'"), { name: "In progress tasks", }); }, rerunOnOpen: true, }, }, }; const realm = await Realm.open(config);
By default, initial subscriptions are only created the first time a realm is opened. If your app needs to rerun this initial subscription every time the app starts, you can set rerunOnOpen to true. 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.
Comprueba el estado de las suscripciones
Puede comprobar el estado de la suscripción para ver si el servidor ha reconocido la suscripción y el dispositivo ha descargado los datos localmente.
You can use subscription state to:
Trigger error handling
Mostrar si la transacción está pendiente o se ha completado
Descubre cuándo se reemplaza un conjunto de suscripciones y deberías obtener una nueva instancia del conjunto de suscripciones para guardar un cambio de suscripción.
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.
New in version 12.0.0.
Node.js v12.0.0 Añadió la enumeración SubscriptionSetState, que puedes utilizar para obtener el estado de una suscripción.
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
You can update a named subscription with a new query. To update a subscription's query, pass the new query and a subscription option with the name of the subscription that you want to update to the MutableSubscriptionSet.add() method. Like adding a new subscription, you must update a subscription within a transaction by calling subscriptions.update().
In the following example, long-running tasks are re-defined to be any tasks that have taken more than 180 minutes.
realm.subscriptions.update((mutableSubs) => { mutableSubs.add( tasks.filtered('status == "completed" && progressMinutes > 180'), { name: "longRunningTasksSubscription", } ); });
Nota
Attempting to update a subscription that has the SubscriptionOptions.throwOnUpdate field set to true throws an exception.
Eliminar suscripciones
Puedes eliminar suscripciones de varias maneras:
Remueve una sola suscripción con una query específica
Remover una sola suscripción con un nombre específico
Remove all subscriptions to a specific object model
Remover todas las suscripciones sin nombre
Remove all subscriptions
When you remove a subscription query, the server also removes synced data from the client device.
Remove a Subscription by Query
You can remove a specific subscription by query by executing a transaction on the subscriptions set. Pass the query to the remove() method on the MutableSubscriptionSet within a transaction.
In the following example, the subscription to tasks with an owner named 'Ben' is removed from the subscriptions set.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific query mutableSubs.remove(tasks.filtered('owner == "Ben"')); });
Remove a Subscription by Name
To remove a specific subscription by name, execute a transaction on the subscriptions set. Within the transaction, pass the name to the removeByName() method on the MutableSubscriptionSet.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific name mutableSubs.removeByName("longRunningTasksSubscription"); });
Eliminar una suscripción por referencia
Si tiene una referencia a una suscripción, puede eliminarla. Para ello, ejecute una transacción en el conjunto de suscripciones. Dentro de la transacción, pase la variable de referencia al método removeSubscription MutableSubscriptionSet en.
let subscriptionReference; realm.subscriptions.update((mutableSubs) => { subscriptionReference = mutableSubs.add(realm.objects("Task")); }); // later.. realm.subscriptions.removeSubscription(subscriptionReference);
Eliminar todas las suscripciones a un tipo de objeto Realm
Para remover todas las suscripciones en un tipo de objeto Realm específico, ejecuta una transacción en el conjunto de suscripciones. Dentro de la transacción, pasa el tipo de objeto Realm como un string al método removeByObjectType en el MutableSubscriptionSet.
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeByObjectType("Team"); });
Remover todas las suscripciones sin nombre
Nueva en la versión v12.0.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 del conjunto de suscripciones llamando a .removeUnnamed() en mutableSubs. .removeUnnamed() devuelve la cantidad de suscripciones sin nombre eliminadas.
// Remove unnamed subscriptions. let numberRemovedSubscriptions = 0; await realm.subscriptions.update((mutableSubs) => { numberRemovedSubscriptions = mutableSubs.removeUnnamed(); });
Remove All Subscriptions
Para eliminar todas las suscripciones del conjunto, ejecute una transacción en dicho conjunto. Llame a removeAll() en el MutableSubscriptionSet dentro de la transacción.
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeAll(); });
Consideraciones sobre el rendimiento
API Efficiency
Administrar múltiples suscripciones con las subscribe() unsubscribe() API y descritas en la sección Suscribirse a consultas es menos eficiente que realizar actualizaciones por lotes cuando administra las suscripciones manualmente.
Para lograr un mejor rendimiento al realizar cambios en varias suscripciones, utiliza la subscriptions API para actualizar todas las suscripciones en una sola transacción. Para aprender cómo, consulta 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.
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.