Managed assinaturas de sincronização - Node.js SDK
Nesta página
- Pré-requisitos
- Inscrever-se para receber queries
- Inscrever-se em uma query
- Assinar uma query sem um nome de assinatura
- Aguarde uma assinatura de query para sincronizar
- Cancelar assinatura de uma query
- Gerenciar assinaturas manualmente
- Obter todas as assinaturas
- Adicionar uma assinatura
- Definir assinaturas iniciais
- Verifique o status das assinaturas
- Estado da assinatura "Concluído"
- Atualizar assinaturas com uma nova query
- Remover subscrições
- Remover uma assinatura por query
- Remover uma assinatura por nome
- Remover uma assinatura por referência
- Remover todas as assinaturas de um tipo de objeto
- Remover todas as assinaturas sem nome
- Remover todas as assinaturas
- Considerações de desempenho
- Eficiência da API
- Atualizações de grupo para melhorar o desempenho
- Requisitos e limitações do Flexible Sync RQL
- Requisitos de inscrição de campos de query indexados
- Operadores de consulta não suportados na sincronização flexível
- Listar queries
- Objetos incorporados ou vinculados
- Limite de tamanho da query
O Flexible Sync usa assinaturas e permissões para determinar quais dados sincronizar com seu aplicativo. Você deve ter pelo menos uma assinatura antes de ler ou escrever em um Realm com o Flexible Sync habilitado. Esta página detalha como managed essas assinaturas.
Você pode adicionar, atualizar e remover assinaturas de query para controlar quais dados são sincronizados com o dispositivo cliente. No Realm Node.js SDK v12.0.0 e posterior, você pode assinar query em vez de gerenciar manualmente as assinaturas ou além delas.
Você não pode criar assinaturas para a ingestão deingestão de dados e objetos assimétricos porque eles só enviam dados para o backend do seu aplicativo.
Importante
Limitações de query do Flexible Sync
As assinaturas do Flexible Sync oferecem suporte apenas a um subconjunto dos operadores de query RQL. Consulte a documentação Flexible Sync RQL das Limitações de do para obter informações sobre quais operadores não são suportados.
Pré-requisitos
Você precisa atender aos seguintes requisitos antes de poder usar o Realm Mobile Sync com o Node.js SDK:
Um cluster de Atlas não fragmentado executando MongoDB 5.0 ou posterior.
Realm JavaScript versão 10.12.0 ou mais tarde.
Além dos requisitos, você precisa configurar o seguinte para usar o Flexible Sync em um cliente Node.js:
Inscrever-se para receber queries
Novo na versão 12.0.0.
O Realm Node.js v12.0.0 adiciona API experimentais que se inscrevem e cancelam a assinatura dos resultados de uma query. Essas API resumem os detalhes de adicionar e remover assinaturas manualmente.
Para todas as assinaturas, você precisa de um usuário autenticado e um termo do Flexible Sync.
Alterado na versão 12,3,0: Dados geoespaciais suportados no Atlas Device Sync
No Realm Node.js SDK v12.3.0 e posterior, você pode criar query para queries geoespaciais. Se você tentar se inscrever em uma query geoespacial com uma versão mais antiga do SDK, receberá um erro de servidor com uma gravação compensatória.
Para mais informações, consulte query de Dados Geoespaciais.
Inscrever-se em uma query
Recomendamos que você nomeie suas assinaturas. Isso torna mais fácil encontrar e gerenciar suas assinaturas. Os nomes das assinaturas devem ser exclusivos. Tentando adicionar uma assinatura com o mesmo nome de uma assinatura existente exibe um erro.
Para assinar uma query:
Consulte os objetos que você deseja ler e gravar.
Ligue
subscribe()
nos resultados da query para criar uma assinatura de sincronização para objetos correspondentes à query.Passe um objeto
SubscriptionOptions
que contenha a propriedadename
parasubscribe()
.
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
Assinar uma query sem um nome de assinatura
Na maioria das vezes, você deve dar um nome às suas assinaturas. Caso contrário, o nome será definido como nulo.
Se você usar filtered()
em uma assinatura de query sem nome, o identificador de assinatura será baseado na query filtered
. Isto significa que toda vez que sua string de query for alterada, o subscribe()
criará uma nova assinatura.
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
Aguarde uma assinatura de query para sincronizar
Quando você assina os resultados de uma query, os resultados não contêm objetos até que os dados sincronizados sejam baixados. Quando for necessário aguardar o término do download dos objetos sincronizados, use waitForSync
. Você pode especificar um comportamento diferente para suas assinaturas e como elas lidam com o Witing para downloads.
Este exemplo utiliza a opção FirstTime
, que é o comportamento padrão. Uma assinatura com comportamento FirstTime
somente aguarda a sincronização terminar quando uma assinatura é criada pela primeira vez.
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", });
As outras opções WaitForSync
suportadas são:
Always
: Aguarde o download dos objetos correspondentes toda vez que seu aplicativo for iniciado. O aplicativo deve ter uma conexão com a Internet em cada lançamento.Never
: Nunca espere para baixar objetos correspondentes. O aplicativo precisa de uma conexão com a Internet para que o usuário se autentique na primeira vez que o aplicativo for iniciado, mas pode ser aberto off-line nas inicializações subsequentes usando credenciais em cache.
Opcionalmente, você pode especificar um valor timeout
para limitar quanto tempo o download de sincronização é executado:
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, });
Cancelar assinatura de uma query
Você pode cancelar a assinatura dos resultados de uma query usando 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();
Isso remove a assinatura da lista de assinaturas ativas, semelhante à remoção manual de uma assinatura.
Uma lista de resultados ainda pode conter objetos após ligar para unsubscribe()
se houver outra assinatura que contenha objetos sobrepostos.
Quando você chama unsubscribe()
, a assinatura associada é removida. As assinaturas são removidas por nome. Se eles não tiverem um nome, unsubscribe()
remove todas as queries que correspondam exatamente à que você chama unsubscribe()
.
O método unsubscribe()
retorna antes que os objetos correspondentes à assinatura removida sejam excluídos do domínio. A sincronização continua em segundo plano com base no novo conjunto de assinaturas.
Gerenciar assinaturas manualmente
Você pode usar a API de Assinaturas para gerenciar manualmente um conjunto de assinaturas para queries específicas em campos consultáveis.
Você pode:
Obter uma lista de todas as assinaturas
Adicionar subscrições
Verificar estado da assinatura
Atualizar assinaturas com novas queries
Remover assinaturas individuais ou todas as assinaturas de um tipo
Quando os dados correspondem à assinatura e têm permissões apropriadas, eles são sincronizados entre os dispositivos e o aplicativo de backend.
Quando você cria uma assinatura, o Realm procura dados correspondentes a uma query em um tipo de objeto específico. Você pode ter assinaturas em vários tipos de objetos diferentes. Você também pode ter várias queries no mesmo tipo de objeto.
Importante
Links de objetos
Você deve adicionar um objeto e seu objeto vinculado ao conjunto de assinaturas para ver um objeto vinculado.
Se os resultados de sua assinatura contiverem um objeto com uma propriedade vinculada a um objeto não contido nos resultados, o link parecerá nulo. Não há como distinguir se o valor dessa propriedade é legitimamente nulo ou se o objeto ao qual ela se vincula existe, mas está fora da exibição da assinatura de query..
Obter todas as assinaturas
Ao usar um domínio sincronizado flexível, você pode acessar um SubscriptionSet
, uma coleção de assinaturas, por meio do realm.subscriptions propriedade.
// get the SubscriptionSet for the realm const subscriptions = realm.subscriptions;
Adicionar uma assinatura
As assinaturas são baseadas nos resultados das query do Realm.
No exemplo seguinte, completed
e progressMinutes
foram definidos como campos consultáveis em um aplicativo do App Services. No código do cliente, criamos queries filtradas e, em seguida, assinamos seus resultados:
Tarefas concluídas
Tarefas concluídas que assumiram mais de 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", }); });
Definir assinaturas iniciais
Você deve ter pelo menos uma assinatura antes de ler ou escrever em um Realm Flexible Sync. Você pode adicionar uma assinatura inicial ao abrir um Realm.
Para definir as assinaturas iniciais, inclua o campo initialSubscriptions
na SyncConfiguration do seu domínio. Dentro do objeto initialSubscriptions
, adicione um campo update
definido para uma chamada de resposta que se inscreve nas 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);
Por padrão, as assinaturas iniciais são criadas somente na primeira vez que um domínio é aberto. Se seu aplicativo precisar executar novamente essa assinatura inicial toda vez que o aplicativo for iniciado, você poderá definir rerunOnOpen
como true
. Talvez você precise fazer isso para executar novamente intervalos de tempo dinâmicos ou outras queries que exijam um novo cálculo de variáveis estáticas para a assinatura.
Verifique o status das assinaturas
Você pode verificar o estado da assinatura para ver se o servidor reconheceu a assinatura e se o dispositivo baixou os dados localmente.
Você pode usar o estado da assinatura para:
Trigger error handling
Mostrar se a transação está pendente ou foi concluída
Descubra quando um conjunto de assinaturas é substituído e você deve obter uma nova instância do conjunto de assinaturas para gravar uma alteração de assinatura
Observação
Estado da assinatura "Concluído"
O estado do conjunto de assinaturas "complete" não significa que a sincronização "está concluída" ou "todos os documentos foram sincronizados". "Completo" significa que as duas coisas a seguir aconteceram:
A assinatura se tornou o conjunto de assinaturas ativo que está sendo atualmente sincronizado com o servidor.
Os documentos que correspondiam à assinatura no momento em que a assinatura foi enviada ao servidor agora estão no dispositivo local. Observe que isso não inclui necessariamente todos os documentos que atualmente correspondem à assinatura.
O SDK do Realm não fornece uma maneira de verificar se todos os documentos que correspondem a uma assinatura foram sincronizados com o dispositivo.
Novo na versão 12.0.0.
Node.js v12.0.0 adicionou o SubscriptionSetState enum que você pode usar para obter o status de uma assinatura.
Estado da assinatura "Concluído"
O estado do conjunto de assinaturas "complete" não significa que a sincronização "está concluída" ou "todos os documentos foram sincronizados". "Completo" significa que as duas coisas a seguir aconteceram:
A assinatura se tornou o conjunto de assinaturas ativo que está sendo atualmente sincronizado com o servidor.
Os documentos que correspondiam à assinatura no momento em que a assinatura foi enviada ao servidor agora estão no dispositivo local. Observe que isso não inclui necessariamente todos os documentos que atualmente correspondem à assinatura.
O SDK do Realm não fornece uma maneira de verificar se todos os documentos que correspondem a uma assinatura foram sincronizados com o dispositivo.
Atualizar assinaturas com uma nova query
Você pode atualizar uma assinatura nomeada com uma nova query. Para atualizar a query de uma assinatura, passe a nova query e uma opção de assinatura com o nome da assinatura que você deseja atualizar para o método MutableSubscriptionSet.add()
. Como adicionar uma nova assinatura, você deve atualizar uma assinatura dentro de uma transação ligando para subscriptions.update()
.
No exemplo a seguir, as tarefas de longa duração são redefinidas como quaisquer tarefas que levaram mais de 180 minutos.
realm.subscriptions.update((mutableSubs) => { mutableSubs.add( tasks.filtered('status == "completed" && progressMinutes > 180'), { name: "longRunningTasksSubscription", } ); });
Observação
A tentativa de atualizar uma assinatura que tenha o campo SubscriptionOptions.throwOnUpdate
definido como true gera uma exceção.
Remover subscrições
Você pode remover assinaturas de várias maneiras:
Remover uma única assinatura com uma query específica
Remover uma única assinatura com um nome específico
Remover todas as assinaturas de um modelo de objeto específico
Remover todas as assinaturas sem nome
Remover todas as assinaturas
Quando você remove uma query de assinatura, o servidor também remove os dados sincronizados do dispositivo cliente.
Remover uma assinatura por query
Você pode remover uma assinatura específica por query executando uma transação no conjunto de assinaturas. Passe a query para o método remove() no MutableSubscriptionSet
dentro de uma transação.
No exemplo a seguir, a assinatura de tarefas com um proprietário chamado 'Ben' é removida do conjunto de assinaturas.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific query mutableSubs.remove(tasks.filtered('owner == "Ben"')); });
Remover uma assinatura por nome
Para remover uma assinatura específica por nome, execute uma transação no conjunto de assinaturas. Dentro da transação, passe o nome para o método removeByName() no MutableSubscriptionSet
.
realm.subscriptions.update((mutableSubs) => { // remove a subscription with a specific name mutableSubs.removeByName("longRunningTasksSubscription"); });
Remover uma assinatura por referência
Se você tiver uma referência a uma assinatura, poderá removê-la. Para isso, execute uma transação no conjunto de assinaturas. Dentro da transação, passe a variável de referência para o método removeSubscription no MutableSubscriptionSet
.
let subscriptionReference; realm.subscriptions.update((mutableSubs) => { subscriptionReference = mutableSubs.add(realm.objects("Task")); }); // later.. realm.subscriptions.removeSubscription(subscriptionReference);
Remover todas as assinaturas de um tipo de objeto
Para remover todas as assinaturas de um tipo de objeto específico, execute uma transação no conjunto de assinaturas. Na transação, passe o tipo de objeto como uma string para o método removeByObjectType no MutableSubscriptionSet
.
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeByObjectType("Team"); });
Remover todas as assinaturas sem nome
Novo na versão v12.0.0.
Você pode querer remover assinaturas não nomeadas que são transitórias ou geradas dinamicamente, mas deixar assinaturas nomeadas em vigor.
Você pode remover todas as assinaturas sem nome da assinatura definida ligando para .removeUnnamed()
em mutableSubs
. .removeUnnamed()
retorna o número de assinaturas sem nome removidas.
// Remove unnamed subscriptions. let numberRemovedSubscriptions = 0; await realm.subscriptions.update((mutableSubs) => { numberRemovedSubscriptions = mutableSubs.removeUnnamed(); });
Remover todas as assinaturas
Para remover todas as assinaturas do conjunto de assinaturas, execute uma transação no conjunto de assinaturas. Chame removeAll() no MutableSubscriptionSet
dentro da transação
realm.subscriptions.update((mutableSubs) => { mutableSubs.removeAll(); });
Considerações de desempenho
Eficiência da API
O gerenciamento de várias assinaturas com as APIs subscribe()
e unsubscribe()
descritas na seção Assinar queries é menos eficiente do que executar atualizações em lote quando você gerencia assinaturas manualmente.
Para obter melhor desempenho ao fazer várias alterações na assinatura, use a API subscriptions
para atualizar todas as assinaturas em uma única transação. Para saber como, consulte Gerenciar assinaturas manualmente.
Atualizações de grupo para melhorar o desempenho
Cada transação de escrita para um conjunto de assinaturas tem um custo de desempenho. Se você precisar fazer várias atualizações em um objeto do Realm durante uma sessão, considere manter objetos editados na memória até que todas as alterações sejam concluídas. Isso melhora o desempenho da sincronização, gravando apenas o objeto completo e atualizado em seu domínio, em vez de cada alteração.
Requisitos e limitações do Flexible Sync RQL
Requisitos de inscrição de campos de query indexados
Adicionar um campo de query indexado à sua aplicação pode melhorar o desempenho de queries simples em dados fortemente particionados. Por exemplo, uma aplicação onde as queries mapeiam fortemente os dados para um dispositivo, armazém ou usuário, como user_id == $0, “641374b03725038381d2e1fb”
, é uma boa candidata para um campo de query indexado. No entanto, um campo de query indexado tem requisitos específicos para uso em uma inscrição de query:
O campo de query indexado deve ser usado em todas as inscrições de query. Não pode estar faltando na query.
O campo de query indexado deve usar uma comparação
==
ouIN
com uma constante pelo menos uma vez na query de inscrição. Por exemplo,user_id == $0, "641374b03725038381d2e1fb"
oustore_id IN $0, {1,2,3}
.
Opcionalmente, você pode incluir uma comparação AND
, desde que o campo consultável indexado seja comparado diretamente com uma constante usando ==
ou IN
pelo menos uma vez. Por exemplo, store_id IN {1,2,3} AND region=="Northeast"
ou store_id == 1 AND (active_promotions < 5 OR num_employees < 10)
.
As consultas inválidas do Flexible Sync em um campo indexado que pode ser consultado incluem consultas em que:
O campo de consulta indexado não utiliza
AND
com o resto da consulta. Por exemplostore_id IN {1,2,3} OR region=="Northeast"
é inválido porque usaOR
em vez deAND
. Da mesma forma,store_id == 1 AND active_promotions < 5 OR num_employees < 10
é inválido porque oAND
só se aplica ao termo ao lado, não à consulta inteira.O campo de consulta indexado não é utilizado em um operador de igualdade. Por exemplo
store_id > 2 AND region=="Northeast"
é inválido porque utiliza apenas o operador>
com o campo de consulta indexado e não tem uma comparação de igualdade.A query está totalmente ausente do campo de query indexado. Por exemplo,
region=="Northeast
outruepredicate
são inválidos porque não contêm o campo de query indexado.
Operadores de consulta não suportados na sincronização flexível
A Flexible Sync tem algumas limitações ao usar operadores RQL. Quando você escreve a assinatura de consulta que determina quais dados sincronizar, o servidor não oferece suporte a esses operadores de consulta. No entanto, você ainda pode usar toda a gama de recursos de RQL para consultar o conjunto de dados sincronizado no aplicativo cliente.
Tipo de operador | Operadores não suportados |
---|---|
Operadores agregados | @avg , @count , @max , @min , @sum |
Sufixos de query | DISTINCT , SORT , LIMIT |
Queries que não diferenciam maiúsculas de minúsculas ([c]
) não podem usar índices de forma eficaz. Sendo assim, queries que não diferenciam maiúsculas de minúsculas não são recomendadas, pois podem causar problemas de desempenho.
A sincronização flexível suporta apenas @count
para campos de array.
Listar queries
A sincronização flexível oferece suporte às listas de query usando o operador IN
.
Você pode consultar uma lista de constantes para ver se ela contém o valor de um campo de consulta:
// Query a constant list for a queryable field value "priority IN { 1, 2, 3 }"
Se um campo de query tiver um valor de array, você poderá consultar para ver se ele contém um valor constante:
// Query an array-valued queryable field for a constant value "'comedy' IN genres"
Aviso
Não é possível comparar duas listas entre si em uma consulta de sincronização flexível. Observe que esta é uma sintaxe válida do Realm Query Language fora das consultas do Flexible Sync.
// 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 incorporados ou vinculados
A Flexible Sync não oferece suporte à consulta de propriedades em objetos ou links embarcados. Por exemplo, obj1.field == "foo"
.
Limite de tamanho da query
O limite de tamanho para qualquer assinatura de query em seu conjunto de assinatura é de 256 kB. Exceder esse limite resulta em um erro de LimitsExceeded.