Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/ /

Gravar dados em um Realm sincronizado - Flutter SDK

Nesta página

  • Determinar quais dados são sincronizados
  • Configuração do App Services
  • Modelo de dados Realm e configuração do cliente
  • Escreva para um domínio sincronizado
  • Gravações bem-sucedidas
  • Compensação de escritas
  • Gravações que não correspondem à assinatura da query
  • Gravações que não correspondem às permissões

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. Para saber mais sobre como ler e gravar dados em um Realm, consulte Ler e gravar dados.

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).

    • Para saber mais sobre como compensar erros de gravação e como evitá-los, consulte a seção Escritas compensatória .

  • 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 deDevice Sync na documentação do Atlas App Services .

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 exemplos nesta página usam um Atlas App Services App com a seguinte configuração Realm Mobile Sync e um aplicativo cliente com o seguinte Modelo de dados Realm e assinaturas do Realm SDK.

O Realm Mobile Sync é configurado com os seguintes campo de query:

  • _id (Sempre incluído)

  • miles

  • 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
}

Os exemplos nesta página usam o seguinte esquema:

@RealmModel()
class _Car {
@MapTo("_id")
@PrimaryKey()
late ObjectId id;
// This is the queryable field
late String ownerId;
late String make;
late String? model;
late int? miles;
}

Usando esse esquema, os exemplos configuram o Realm sincronizado para sincronizar objeto correspondentes a esta query de assinatura:

final app = App(AppConfiguration(APP_ID));
final user = await app.logIn(Credentials.anonymous());
final config = Configuration.flexibleSync(user, [Car.schema]);
final realm = Realm(config);
// Add subscriptions
realm.subscriptions.update((mutableSubscriptions) {
// Get Cars from Atlas that match the Realm Query Language query.
// Uses the queryable field `miles`.
// Query matches cars with less than 100 miles or `null` miles.
final newCarQuery = realm.query<Car>("miles < 100 OR miles == \$0", [null]);
mutableSubscriptions.add(newCarQuery, name: "new-car-subscription");
});
await realm.subscriptions.waitForSynchronization();

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.

Quando a gravação corresponde às permissões doAtlas App Services e à query de assinatura doFlexible Sync no cliente, o SDK do Realm Flutter 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.

// Per the Device Sync permissions, users can only read and write data
// where the `Car.ownerId` property matches their own user ID.
final userId = user.id;
realm.write(() {
// WRITE SUCCEEDS
// `newCar` is successfully written to the realm and synced to Atlas
// because it's data matches the subscription query (miles < 100)
// and it's `ownerId` field matches the user ID.
final newCar = Car(ObjectId(), userId, 'Toyota', miles: 2);
realm.add(newCar);
});

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:

  1. 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.

  2. 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.

  3. O servidor envia uma operação de reversão, chamada de "escrita compensatória", de volta ao cliente.

  4. 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.

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.

Se você quiser gravar um objeto que não corresponde à assinatura de query, abra um domínio diferente onde o objeto corresponde à assinatura de query. Como alternativa, você pode gravar o objeto em um domínio local que não imponha permissões ou consultas de assinatura.

Dada a configuração do domínio sincronizado acima, a tentativa de gravar esse objeto não corresponde à assinatura da query:

final carId = ObjectId();
final ownerId = app.currentUser!.id;
realm.write(() {
// WRITE REVERTED BY QUERY SUBSCRIPTION COMPENSATING WRITE
// `oldCar` is initially written to the realm, then later removed
// in a compensating write when the server processes the write.
// This is because the `miles` property of `oldCar` doesn't match
// the subscription query, which is only for cars with less than 100 miles.
final oldCar = Car(carId, ownerId, 'Honda', miles: 90000);
realm.add(oldCar);
});
// Let changes sync to and from server
await realm.syncSession.waitForUpload();
await realm.syncSession.waitForDownload();
final noCar = realm.find<Car>(carId);
// The Car is no longer in the realm because of
// the compensating write from the server.
expect(noCar, isNull);

A mensagem de erro nos registros do lado do cliente nesse cenário é:

[INFO] Realm: 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)
[INFO] Realm: Connection[1]: Session[1]: Reporting compensating write
for client version 21 in server version 2877: Client attempted a write that
is outside of permissions or query filters; it has been reverted
[ERROR] Realm: SyncSessionError message: Client attempted a write that
is outside of permissions or query filters; it has been reverted
Logs: https://services.cloud.mongodb.com/groups/5f60207f14dfb25d23101102/apps/639340a757271cb5e3a0f0cf/logs?co_id=6424433efb0c6bbcc330347c
category: SyncErrorCategory.session code: SyncSessionErrorCode.compensatingWrite isFatal: false

A mensagem de erro nos registros do App Services nesse cenário é:

Error:
Client attempted a write that is outside of permissions or query filters; it has been reverted (ProtocolErrorCode=231)
Details:
{
"Car": {
"6424433fd4d9f52ee93ad590": "write to \"6424433fd4d9f52ee93ad590\" in table \"Car\" not allowed; object is outside of the current query view"
}
}

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.

Dadas as permissões na configuração 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:

final carId = 'someOtherId';
realm.write(() {
// WRITE REVERTED BY PERMISSION ERROR
// `otherUsersCar` is initially written to the realm, then removed upon synchronization
// because it's `ownerId` property doesn't match the user ID of the user
// making the request.
final otherUsersCar = Car(ObjectId(), carId, 'Ford');
realm.add(otherUsersCar);
});
// sync changes
await realm.syncSession.waitForUpload();
await realm.syncSession.waitForDownload();
final noCar = realm.find<Car>(carId);
// The Car is no longer in the realm because of
// the compensating write from the server.
expect(noCar, isNull);

O erro do cliente nesse cenário é o mesmo de quando você tenta gravar um objeto que está fora das permissões do App Services:

[INFO] Realm: 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)
[INFO] Realm: Connection[1]: Session[1]: Reporting compensating write
for client version 25 in server version 2879: Client attempted a write that
is outside of permissions or query filters; it has been reverted
[ERROR] Realm: SyncSessionError message: Client attempted a write that
is outside of permissions or query filters; it has been reverted
Logs: https://services.cloud.mongodb.com/groups/5f60207f14dfb25d23101102/apps/639340a757271cb5e3a0f0cf/logs?co_id=6424433efb0c6bbcc330347c
category: SyncErrorCategory.session code: SyncSessionErrorCode.compensatingWrite isFatal: false

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:

Error:
Client attempted a write that is outside of permissions or query filters;
it has been reverted (ProtocolErrorCode=231)
Details:
{
"Car": {
"6424433fd4d9f52ee93ad591": "write to \"6424433fd4d9f52ee93ad591\" in table \"Car\" was denied by write filter in role \"owner-read-write\""
}
}

Voltar

Gerir subscrições