Gravar dados em um domínio sincronizado - Swift SDK
Nesta página
- Visão geral
- Determinar quais dados são sincronizados
- Configuração do App Services
- Modelo de dados Realm e configuração do cliente
- Quais dados são sincronizados?
- Escreva para um domínio sincronizado
- Gravações bem-sucedidas
- Compensação de escritas
- Informações de erro de gravação compensatórias
- Gravações que não correspondem à assinatura da query
- Gravações que não correspondem às permissões
- Escritas em grupo para melhorar o desempenho
- Não escreva para um Realm sincronizado em uma extensão de aplicativo
- Falhas relacionadas à abertura de um Realm sincronizado em vários processos
- Alternativas para escrever em um Realm sincronizado em uma extensão de aplicativo
- Passar dados no disco
- Comunique-se diretamente com a collection de apoio Atlas
Visão geral
Ao gravar dados em um Realm sincronizado usando o Flexible Sync, você pode usar a mesma API que ao gravar em um Realm local. No entanto, há algumas diferenças de comportamento que devem ser levadas em conta ao desenvolver seu aplicativo.
Quando você escreve em um Realm sincronizado, suas operações de escrita devem corresponder aos dois itens a seguir:
- A query de assinatura de sincronização.
Se sua operação de gravação não corresponder à query na assinatura, a gravação será revertida com um erro de gravação compensatória não fatal (ErrorCompensatingWrite).
- As permissões em seu App Services App.
Se você tentar gravar dados que não correspondem à expressão de permissões, a gravação será revertida com um erro de permissão negada não fatal. No cliente, isso aparece como um erro (ErrorCompensatingWrite). No servidor, você pode ver mais detalhes sobre como a gravação foi negada por um filtro de escrita na role.
Para saber mais sobre como configurar permissões para seu aplicativo, consulte Permissões baseadas em funções e o Guia de permissões de Device Sync na documentação do App Services.
Aviso
A sincronização de vários processos não é suportada
Atualmente, o Device Sync não permite a abertura ou gravação em um domínio sincronizado a partir de mais de um processo. Para obter mais informações, incluindo alternativas sugeridas, consulte: Não escreva para um domínio Realm em uma extensão de aplicativo.
Determinar quais dados são sincronizados
Os dados que você pode gravar em um Realm sincronizado são a interseção da configuração do Realm Mobile Sync, suas permissões e a query de assinatura do Flexible Sync que você usa quando abre o Realm.
Os exemplos nesta página usam as seguintes configurações e modelos:
Configuração do App Services
O Realm Mobile Sync é configurado com os seguintes campo de query:
_id
(Sempre incluído)complexity
ownerId
O App Services App tem permissões configuradas para permitir que os usuários leiam e escrevam somente seus próprios dados:
{ "name": "owner-read-write", "apply_when": {}, "document_filters": { "read": { "ownerId": "%%user.id" }, "write": { "ownerId": "%%user.id" } }, "read": true, "write": true }
Modelo de dados Realm e configuração do cliente
Os exemplos nesta página usam o seguinte modelo de objeto:
class Item: Object { true) var _id: ObjectId (primaryKey: var ownerId: String var itemName: String var complexity: Int }
Utilizando esse modelo de objetos, a configuração do Realm sincronizado sincroniza objeto que correspondem à query onde o valor da propriedade complexity
é menor ou igual a 4
:
let app = App(id: YOUR_APP_ID_HERE) do { let user = try await app.login(credentials: Credentials.anonymous) do { var flexSyncConfig = user.flexibleSyncConfiguration() flexSyncConfig.objectTypes = [Item.self] let realm = try await Realm(configuration: flexSyncConfig) let subscriptions = realm.subscriptions try await subscriptions.update { subscriptions.append( QuerySubscription<Item>(name: "simple-items") { $0.complexity <= 4 }) } print("Successfully opened realm: \(realm)") } catch { print("Failed to open realm: \(error.localizedDescription)") // handle error } } catch { fatalError("Login failed: \(error.localizedDescription)") }
Quais dados são sincronizados?
A query de assinatura combinada com as permissões significa que o domínio sincronizado sincroniza apenas objetos em que:
O
ownerId
corresponde aouser.id
do usuário conectado (a partir das permissões)O valor da propriedade
complexity
é menor ou igual a4
(da query de assinatura)
Qualquer objeto na Atlas collection em que ownerId
não corresponda ao user.id
do usuário conectado ou em que o valor da propriedade complexity
seja maior que 4
não pode ser sincronizado com esse Realm.
Escreva para um domínio sincronizado
As gravações nos domínios do Flexible Sync podem se enquadrar em uma de duas categorias:
Gravações bem- sucedidas: o objeto gravado corresponde à assinatura da query e às permissões do usuário. O objeto é gravado com êxito no Realm e sincroniza com êxito com o backend do App Services e outros dispositivos.
Escritas compensatórias: quando o objeto de escrita não corresponde à query de assinatura, ou quando o usuário não tem permissões suficientes para realizar a escrita, o Realm reverte a escrita ilegal.
Gravações bem-sucedidas
Quando a gravação corresponde às permissões e à query de inscrição do Flexible Sync no cliente, o Realm Swift SDK pode gravar o objeto com êxito no domínio sincronizado. Este objeto é sincronizado com o backend do Atlas App Services quando o dispositivo tem uma conexão de rede.
// This write falls within the subscription query and complies // with the Device Sync permissions, so this write should succeed. do { let learnRealm = Item() learnRealm.ownerId = user.id learnRealm.itemName = "Learn Realm CRUD stuff" learnRealm.complexity = 3 try realm.write { realm.add(learnRealm) } } catch { print("Failed to write to realm: \(error.localizedDescription)") }
Compensação de escritas
Em alguns casos, uma escrita que inicialmente parece bem-sucedida é, na verdade, uma escrita ilegal. Nesses casos, o objeto grava no reconhecimento de data center, mas quando o reconhecimento de data center sincroniza com o backend, o Realm reverte a escrita em uma operação de erro não fatal chamada escrita compensatória. As gravações compensatórias podem ocorrer quando:
As gravações não correspondem à assinatura da query: O objeto gravado corresponde às permissões do usuário, mas não corresponde à assinatura da query.
As gravações não correspondem às permissões: o objeto gravado corresponde à assinatura da query, mas não corresponde às permissões do usuário.
Em mais detalhes, quando você grava dados que estão fora dos limites de uma assinatura de query ou não correspondem às permissões do usuário, ocorre o seguinte:
Como o Realm do cliente não tem nenhum conceito de gravações "ilegais", a gravação inicialmente é bem-sucedida até que o Realm resolva o conjunto de alterações com o backend do App Services.
Após a sincronização, o servidor aplica as regras e permissões. O servidor determina que o usuário não tem autorização para realizar a gravação.
O servidor envia uma operação de reversão, chamada de "escrita compensatória", de volta ao cliente.
O Realm do cliente reverte a operação de escrita ilegal.
Qualquer escrita do lado do cliente em um determinado objeto entre uma escrita ilegal nesse objeto e a escrita compensatória correspondente será perdida.
Na prática, isso pode parecer um objeto sendo gravado no Realm e desaparecer depois que o servidor enviar a gravação compensatória de volta ao cliente.
Para saber mais sobre erros de permissão negada, erros de gravação compensatórios e outros tipos de erro do Device Sync , consulte Erros de sincronização na documentação do Atlas App Services .
Os registrosAtlas App Services contêm mais informações sobre o motivo de um erro de gravação compensatório.
Informações de erro de gravação compensatórias
Novidade na versão 10.37.0 .
Você pode obter informações adicionais no cliente sobre o motivo de ocorrer uma gravação compensatória. O Swift SDK expõe um campo compensatingWriteInfo em um SyncError cujo código é .writeRejected
. Você pode acessar essas informações por meio do manipulador de erros de sincronização.
Este campo contém uma array de objetos RLMCompensatingWriteInfo , que fornecem:
O
objectType
do objeto que o cliente tentou escreverO
primaryKey
do objeto específicoO
reason
para o erro de gravação compensatória
Essas informações são as mesmas que você pode encontrar nos registros do App Services. Ele é exposto no cliente para fins de conveniência e depuração.
Exemplo
Este manipulador de erros mostra um exemplo de como você pode registrar informações para compensar erros de escrita:
myApp.syncManager.errorHandler = { syncError, session in if let thisError = syncError as? SyncError { switch thisError.code { // ... additional SyncError.code cases ... case .writeRejected: if let compensatingWriteErrorInfo = thisError.compensatingWriteInfo { for anError in compensatingWriteErrorInfo { print("A write was rejected with a compensating write error") print("The write to object type: \(anError.objectType)") print("With primary key of: \(anError.primaryKey)") print("Was rejected because: \(anError.reason)") } } } } }
O exemplo de manipulador de erros acima produz essa saída quando ocorre um erro de gravação compensatório:
A write was rejected with a compensating write error The write to object type: Optional("Item") With primary key of: objectId(641382026852d9220b2e2bbf) Was rejected because: Optional("write to \"641382026852d9220b2e2bbf\" in table \"Item\" not allowed; object is outside of the current query view")
O
Optional("Item")
nesta mensagem é umItem
objeto usado no aplicativo Swift Template.A chave primária é o
objectId
do objeto específico que o cliente tentou escrever.O
table \"Item"\
refere-se à collection Atlas onde este objeto sincronizaria.O motivo
object is outside of the current query view
nesse exemplo é porque a assinatura de query foi definida para exigir que a propriedadeisComplete
do objeto fossetrue
, e o cliente tentou gravar um objeto em que essa propriedade erafalse
.
Gravações que não correspondem à assinatura da query
Você só pode gravar objeto em um Realm do Flexible Sync se eles corresponderem à query. Se você executar uma gravação que não corresponda à query de assinatura, o Realm gravará inicialmente o objeto, mas depois executará uma gravação compensatória. Esta é uma operação não fatal que reverte uma gravação ilegal que não corresponde à query de assinatura.
Na prática, isso pode parecer que a gravação foi bem-sucedida, mas o objeto "desaparece" quando o Realm sincroniza com o backend do App Services e executa a gravação compensatória.
Se você quiser gravar um objeto que não corresponde à query, deverá abrir um Realm diferente onde o objeto corresponde à query. Como alternativa, você pode gravar o objeto em um domínio não sincronizado que não impõe permissões ou consultas de assinatura.
exemplo de código
Dada a configuração do Realm Flexible Sync acima, a tentativa de gravar esse objeto não corresponde à query subscription:
do { let fixTheBug = Item() fixTheBug.ownerId = user.id fixTheBug.itemName = "Fix the bug with the failing method" // The complexity of this item is `7`. This is outside the bounds // of the subscription query, so this write triggers a compensating write. fixTheBug.complexity = 7 try realm.write { realm.add(fixTheBug) } } catch { print("Failed to write to realm: \(error.localizedDescription)") }
Erro do cliente
A mensagem de erro nos registros do lado do cliente nesse cenário é:
Sync: Connection[1]: Session[1]: Received: ERROR "Client attempted a write that is outside of permissions or query filters; it has been reverted" (error_code=231, try_again=true, error_action=Warning)
Erro do App Services
A mensagem de erro nos registros do App Services nesse cenário é:
"FlexibleSync_Item": { "63bdfc40f16be7b1e8c7e4b7": "write to \"63bdfc40f16be7b1e8c7e4b7\" in table \"FlexibleSync_Item\" not allowed; object is outside of the current query view" }
Gravações que não correspondem às permissões
A tentativa de gravar no cliente também pode trigger um erro de gravação compensatório quando o objeto não corresponde às permissões de gravação no servidor do usuário.
No cliente, esse tipo de gravação se comporta da mesma forma que uma gravação que não corresponde à assinatura da query. Na prática, isso pode parecer que a gravação foi bem-sucedida, mas o objeto "desaparece" quando o Realm sincroniza com o backend do App Services e executa a gravação compensatória.
exemplo de código
Dadas as permissões na Configuração do Realm Mobile Sync detalhadas acima, tentar gravar um objeto em que a propriedade ownerId
não corresponde ao user.id
do usuário conectado não é uma gravação legal:
do { let itemWithWrongOwner = Item() // The `ownerId` of this item does not match the `user.id` of the logged-in // user. The user does not have permissions to make this write, so // it triggers a compensating write. itemWithWrongOwner.ownerId = "This string does not match the user.id" itemWithWrongOwner.itemName = "Write code that generates a permission error" itemWithWrongOwner.complexity = 1 try realm.write { realm.add(itemWithWrongOwner) } } catch { print("Failed to write to realm: \(error.localizedDescription)") }
Erro do cliente
O erro do cliente nesse cenário é o mesmo de quando você tenta gravar um objeto que está fora do filtro de query:
Sync: Connection[1]: Session[1]: Received: ERROR "Client attempted a write that is outside of permissions or query filters; it has been reverted" (error_code=231, try_again=true, error_action=Warning)
Erro do App Services
A mensagem de erro nos registros do App Services fornece algumas informações adicionais para ajudá-lo a determinar que é um problema de permissões e não um problema de assinatura de query. Neste exemplo, a mensagem de erro mostra que o objeto não corresponde à role do usuário:
"FlexibleSync_Item": { "63bdfc40f16be7b1e8c7e4b8": "write to \"63bdfc40f16be7b1e8c7e4b8\" in table \"FlexibleSync_Item\" was denied by write filter in role \"owner-read-write\"" }
Escritas em 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.
Não escreva para um Realm sincronizado em uma extensão de aplicativo
Se você estiver desenvolvendo um aplicativo que usa extensões de aplicativo, como uma extensão de compartilhamento, evite gravar em um Realm sincronizado nessa extensão. O Realm Mobile Sync oferece suporte à abertura de um Realm sincronizado em no máximo um processo. Na prática, isso significa que, se o seu aplicativo usar um Realm em uma Extensão de Aplicativo, ele poderá falhar de forma intermitente.
Falhas relacionadas à abertura de um Realm sincronizado em vários processos
Se você tentar abrir um Realm sincronizado em uma Extensão de Compartilhamento ou outra Extensão de Aplicativo, e esse Realm não estiver aberto no aplicativo principal, uma gravação de uma Extensão de Compartilhamento poderá ser bem-sucedida. No entanto, se o Realm sincronizado já estiver aberto no aplicativo principal ou estiver sincronizando dados em segundo plano, você poderá ver uma falha relacionada a Realm::MultiSyncAgents
. Nesse cenário, talvez seja necessário reiniciar o dispositivo.
Alternativas para escrever em um Realm sincronizado em uma extensão de aplicativo
Se você precisar ler ou gravar em um Realm a partir de uma extensão de aplicativo, existem algumas alternativas recomendadas:
Offline-first: passe dados no disco de ou para o aplicativo principal
Sempre atualizado : comunique-se diretamente com a collection de apoio do Atlas por meio de uma conexão de rede
Passar dados no disco
Se a funcionalidade offline-first for a consideração mais importante para sua aplicação, você poderá passar dados em disco de ou para sua aplicação principal. Você pode copiar objeto para um Realm não sincronizado e lê-lo e compartilhá-lo entre aplicativos em um grupo de aplicativos. Ou você pode usar uma fila no disco para enviar os dados de ou para o aplicativo principal e somente escrever no Realm sincronizado a partir daqui. Em seguida, independentemente da conectividade de rede do dispositivo, as informações podem ser compartilhadas a qualquer momento de ou para a extensão de aplicativo.
Comunique-se diretamente com a collection de apoio Atlas
Se ter as informações sempre atualizadas em todos os dispositivos é a consideração mais importante para o seu aplicativo, você pode ler ou gravar dados diretamente de ou para a coleção de apoio do Atlas em toda a rede. Dependendo de suas necessidades, você pode querer usar uma destas ferramentas para se comunicar diretamente com Atlas:
Query Atlas com o Realm Swift SDK MongoClient
Passar dados para uma função do App Services
Faça chamadas HTTPS com a Atlas Data API
Em seguida, qualquer dispositivo que tenha uma conexão de rede está sempre obtendo as informações mais atualizadas, sem esperar que o usuário abra seu aplicativo principal, como na opção acima.
Essa opção exige que o dispositivo do usuário tenha uma conexão de rede ao usar a extensão de aplicativo. Como alternativa, você pode verificar se há uma conexão de rede. Em seguida, use a opção no disco acima caso o dispositivo do usuário não tenha conectividade de rede.