Gerenciar assinaturas de sincronização - Flutter SDK
Nesta página
- Pré-requisitos
- Alinhe assinaturas com aplicativo de backend
- Inscrever-se para receber queries
- Inscrever-se em uma query
- Aguarde uma assinatura de query para sincronizar
- Cancelar assinatura de uma query
- Gerenciar assinaturas manualmente
- Obter assinaturas
- Adicionar uma query ao conjunto de assinaturas
- Atualizar assinaturas com uma nova query
- Remover subscrições
- Aguarde as alterações na assinatura para sincronizar
- Estado da assinatura
- 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
- Considerações de desempenho
- Eficiência da API
- Atualizações de grupo para melhorar o desempenho
O Atlas Device Sync com Flexible Sync usa assinaturas e permissões para determinar quais dados sincronizar entre o Atlas e seu aplicativo.
Você pode adicionar, atualizar e remover assinaturas de query para determinar quais dados são sincronizados com o dispositivo cliente.
Pré-requisitos
Observação
Pré-requisitos do Flexible Sync
A ativação da Flexible Sync em seu aplicativo requer um cluster de Atlas não fragmentado que esteja executando o MongoDB 5.0 ou superior
Para usar a Flexible Sync em um aplicativo Flutter:
Alinhe assinaturas com aplicativo de backend
Suas queries de assinatura do lado do cliente devem estar alinhadas com a configuração do Device Sync em seu aplicativo de serviços de aplicativo de backend.
Suas query de assinatura podem:
Consulta todos os objetos de um tipo. Crie a consulta usando Realm.all().
Objetos de query que correspondem aos campos de query do aplicativo de backend. Crie a query usando Realm.query() e uma query RQL que inclui um ou mais campos de query. O Realm SDK lançará um erro se você tentar criar uma assinatura usando campos que não podem ser consultados.
Para saber mais sobre como configurar campos consultáveis, consulte Campos de query na documentação do Atlas App Services .
Para saber mais sobre as limitações do uso da Realm Query Language com o Flexible Sync, consulte a seção Limitações da RQL do Flexible Sync.
Inscrever-se para receber queries
Novidade na versão v1,6,0.
O Flutter v1.6.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 de um domínio sincronizado.
Se você precisar de mais controle sobre as assinaturas por motivos de otimização de desempenho ou lógica de negócios, poderá gerenciar manualmente o conjunto de assinaturas usando a API subscriptions
. Consulte a seção Considerações sobre desempenho nesta página para obter mais informações.
Inscrever-se em uma query
Você pode assinar o RealmResults
de uma query usando o subscribe() método. Quando chamado, o SDK cria a nova assinatura e a adiciona ao MutableSubscriptionSet
, semelhante à criação manual de assinaturas.
Opcionalmente, você pode passar um nome de assinatura exclusivo para a query. Se você adicionar uma assinatura com o mesmo nome de uma assinatura existente, o SDK substituirá a assinatura existente.
Se você não passar um nome de assinatura, o nome será definido como null
e o identificador de assinatura será baseado na string de query. Isto significa que toda vez que sua string de query muda, o subscribe()
cria uma nova assinatura.
Para assinar uma query, passe os seguintes argumentos para subscribe()
:
RealmResults query
: Obrigatório. Um objetoRealmResults
que você pode criar usando a Realm Query Language.String name
: Opcional. Nome da assinatura que você pode consultar.bool update
: Opcional. Quando verdadeiro, adicionar uma assinatura com um nome existente substitui a query existente pela nova query. Quando falso, o SDK lança uma exceção para assinaturas duplicadas. Use apenas com assinaturas nomeadas.
No exemplo a seguir, assinamos duas novas query nomeadas.
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");
Dica
Especificar um nome de assinatura
Recomendamos que você sempre especifique um nome para a assinatura, especialmente se seu aplicativo usar várias assinaturas. Isso torna mais fácil encontrar e gerenciar suas assinaturas.
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, configure o waitForSyncMode opção.
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.
final bigPlaneQuery = realm.query<Plane>("numSeats > 100"); final planeSubscription = await bigPlaneQuery.subscribe( name: "firstTimeSync", waitForSyncMode: WaitForSyncMode.firstTime, );
As outras opções waitForSyncMode
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 offline nas execuções subsequentes usando credenciais em cache.
Opcionalmente, você pode especificar um Token de cancelamento para limitar quanto tempo o download de sincronização é executado:
final bigPlaneQuery = realm.query<Plane>("numSeats > 200"); final planeSubscription = await bigPlaneQuery.subscribe( name: "alwaysWaitSync", waitForSyncMode: WaitForSyncMode.always, cancellationToken: TimeoutCancellationToken(Duration(seconds: 5)), );
Cancelar assinatura de uma query
As assinaturas persistem entre as sessões de usuário, a menos que você cancele a assinatura delas. Você pode cancelar a assinatura dos resultados de uma query usando cancelar a assinatura ().
Isso remove a assinatura da lista de assinaturas ativas, semelhante à remoção manual de uma assinatura. Observe que a lista de resultados ainda pode conter objetos depois de ligar unsubscribe()
se houver outra assinatura que contenha objetos sobrepostos.
Quando você chama unsubscribe()
em uma query, o SDK remove todas as assinaturas com queries que correspondem exatamente à que você chama unsubscribe()
. Esse método retorna antes que o objeto correspondente à assinatura removida seja excluído do Realm. A sincronização continua em segundo plano com base no novo conjunto de assinaturas.
planeQuery.unsubscribe(); trainQuery.unsubscribe();
Gerenciar assinaturas manualmente
Ao configurar o Flexible Sync no backend, você especifica quais campos seu aplicativo cliente pode executar uma query. No aplicativo do cliente, use o realm.Subscriptions propriedade para gerenciar um conjunto de assinaturas para queries específicas em campos consultáveis.
Você pode fazer o seguinte com suas assinaturas:
Obter uma lista de todas as assinaturas
Adicionar subscrições
Verificar estado da assinatura
Atualizar uma assinatura com uma nova query
Remover subscrições
Quando os dados correspondem à assinatura e o usuário autenticado tem as permissões apropriadas, o Device Sync sincroniza os dados de backend com o aplicativo cliente.
Os conjuntos de assinaturas persistem entre sessões, mesmo que você não inclua mais a assinatura em seu código. As informações de assinatura são armazenadas no arquivo de reconhecimento de data center do Realm sincronizado. Você deve remover explicitamente uma assinatura para que pare de tentar sincronizar os dados correspondentes.
Você pode especificar um nome de string para sua assinatura. Se você não der um nome à sua assinatura, o nome será definido como null
.
Quando você cria uma assinatura, o Realm procura dados correspondentes a uma query em um Tipo de objeto de Realm específico. Em suas assinaturas do Flexible Sync, você pode ter assinaturas em vários Tipo de objeto de Realm diferentes ou várias query no mesmo Tipo de objeto de Realm.
Obter assinaturas
Ao usar o Flexible Sync, você pode acessar um conjunto de assinaturas , uma collection de assinaturas, por meio da Realm.subscriptions
propriedade .
Você pode usar esse conjunto de assinaturas para adicionar query a essa lista de assinaturas e atualizar assinaturas existentes, conforme mostrado nos exemplos abaixo.
final subscriptions = realm.subscriptions;
Adicionar uma query ao conjunto de assinaturas
Você deve realizar todas as mutações no conjunto de assinaturas dentro de um bloco de atualização. Para criar um bloco de atualização, chame SubscriptionSet.update().
A função de retorno de chamada do bloco de atualização inclui um MutableSubscriptionSet() objeto como argumento. Você pode modificar seu método no SubscriptionSet
para adicionar uma query à assinatura.
Importante
Flexible Sync não é compatível com todos os operadores disponíveis no RQL. Consulte LimitaçõesFlexible Sync RQL de sincronização para obter detalhes.
O método MutableSubscriptionSet.add()
utiliza três argumentos:
RealmResults query
: Obrigatório. Um objetoRealmResults
que você pode criar usando a query RealmQL.String name
: Opcional. Nome da assinatura que você pode consultar.bool update
: Opcional. Quando verdadeiro, adicionar uma assinatura com um nome existente substitui a query existente pela nova query. Use apenas com assinaturas nomeadas.
Observação
assinaturas duplicadas
Se você adicionar uma assinatura duplicada sem nome com a mesma query, o Realm a removerá automaticamente; adicionar uma assinatura nomeada idêntica é um não operacional . Portanto, em ambos os casos, as assinaturas duplicadas são ignoradas.
Você pode adicionar uma única query ou várias queries em lote em um bloco SubscriptionSet.update
. Executar atualizações de query é uma operação cara no servidor. É altamente recomendável projetar seu aplicativo para minimizar as atualizações de assinatura. Você pode fazer isso criando todas as assinaturas em um único bloco de atualização na primeira vez que o usuário iniciar o aplicativo e agrupando em lote quaisquer alterações de acompanhamento no conjunto de assinaturas.
No exemplo abaixo, assinamos duas query.
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();
Atualizar assinaturas com uma nova query
Você pode atualizar uma assinatura nomeada com uma nova query. Para atualizar a query de uma assinatura, abra um bloco de atualização com SubscriptionSet.update()
. Na função de retorno de chamada do bloco de atualização, passe os seguintes argumentos para MutableSubscriptionSet.add()
:
A nova query
O nome da assinatura que você deseja atualizar
update: true
Você não pode atualizar uma assinatura sem nome. Como alternativa, você pode excluir a assinatura sem nome e criar uma nova assinatura com a query desejada.
No exemplo a seguir, trechos longos são redefinidos como quaisquer trechos que tenham mais de 10 vagões.
final longerTrainQuery = realm.query<Train>("numCars > 10"); realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.add(longerTrainQuery, name: 'long-trains', update: true); });
Remover subscrições
Para remover assinaturas do conjunto de assinaturas, você pode:
Remover uma única assinatura com a query fornecida
Remover uma única assinatura com o nome fornecido
Remover uma única assinatura com a referência de assinatura
Remover todas as assinaturas para um Tipo de objeto de Realm
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
Dentro de um bloco de atualização, você pode remover uma assinatura específica por query. Abra um bloco de atualização com SubscriptionSet.update()
. Passe o Subscription
para MutableSubscriptionSet.removeByQuery().
No exemplo a seguir, a assinatura de todos os objetos Plane
é removida.
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByQuery(realm.all<Plane>()); });
Remover uma assinatura por nome
Dentro de um bloco de atualização, você pode remover uma assinatura específica por nome. Passe o nome para MutableSubscriptionSet.removeByName()
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByName('long-trains'); });
Remover uma assinatura por referência
Você pode remover uma assinatura se tiver uma referência à sua Assinatura evento. Dentro de um bloco de atualização de assinatura, passe a Subscription
referência para MutableSubscriptionSet.remove().
final sub = realm.subscriptions[0]; realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.remove(sub); });
Remover todas as assinaturas de um Tipo de objeto de Realm
Você pode remover todas as assinaturas de um determinado tipo de objeto do Realm. Dentro de um bloco de atualização de assinatura, ligue para MutableSubscriptionSet.removeByType().
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.removeByType<Train>(); });
Remover todas as assinaturas
Em um bloco de atualização de assinatura, você pode remover todas as assinaturas sem nome do conjunto de assinaturas com MutableSubscriptionSet.clear().
realm.subscriptions.update((MutableSubscriptionSet mutableSubscriptions) { mutableSubscriptions.clear(); });
Aguarde as alterações na assinatura para sincronizar
Mutar o conjunto de assinaturas em um bloco de atualização é apenas uma parte da alteração de uma assinatura. Após a alteração da assinatura local, o Realm sincroniza com o servidor para resolver quaisquer atualizações nos dados devido à alteração da assinatura. Isso inclui adicionar ou remover dados do domínio sincronizado.
Use Realm.subscriptions.waitForSynchronization() para aguardar o servidor confirmar este conjunto de assinaturas. Se o servidor rejeitar a alteração e uma exceção for lançada.
Uma exceção pode ocorrer se:
Você se inscreve em uma query não suportada. A assinatura de uma query não suportada pausará a sincronização. Para retomar a sincronização, remova a query não suportada.
Você está executando uma ação inválida, como adicionar um objeto que não corresponde a uma assinatura. Este Atlas Triggers um reinício do cliente: os dados são apagados do domínio e uma nova cópia dos dados é criada sem nenhuma assinatura no conjunto.
await realm.subscriptions.waitForSynchronization();
Estado da assinatura
Use o realm.subscriptions.state propriedade para ler o estado atual do conjunto de assinaturas.
O superseded
estado é um SubscriptionSetState que pode ocorrer quando outro thread atualiza uma assinatura em uma instância diferente do conjunto de assinatura. Se o estado se tornar superseded
, você deverá obter uma nova instância do conjunto de assinaturas antes de poder atualizá-lo.
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.
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.
Considerações de desempenho
Eficiência da API
O gerenciamento de várias assinaturas com a API .subscribe()
descrita na seção Assinar queries é menos eficiente do que executar atualizações em lote quando você gerencia assinaturas manualmente por meio da API do conjunto de assinaturas. Para obter melhor desempenho ao fazer várias alterações na assinatura, use a API subscriptions.update
descrita na seção 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.