Write Data to a Synced Realm - C++ 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
- A gravação não corresponde à assinatura da query
- A gravação não corresponde às permissões
- Informações de erro de gravação compensatórias
- Escritas em grupo para melhorar o desempenho
When writing data to a synced realm using Flexible Sync, you can use the same APIs as when performing CRUD operations on a non-synced realm. However, there are some differences in behavior to keep in mind as you develop your application.
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
As permissões em seu App Services App
Se você tentar gravar dados que não correspondam à assinatura da query ou às permissões do usuário, o Realm reverterá a gravação com uma operação de erro não fatal chamada gravação compensatória.
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 .
Determinar quais dados são sincronizados
Os dados que você pode gravar em um Realm sincronizado são determinados pelo seguinte:
Sua configuração do Realm Mobile Sync
Permissões em sua aplicação
A query de assinatura do Flexible Sync usada quando você abre o domínio
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.
Neste exemplo, o aplicativo cliente usa o seguinte modelo de objeto:
struct Item { realm::primary_key<realm::object_id> _id{realm::object_id::generate()}; std::string ownerId; std::string itemName; int64_t complexity; }; REALM_SCHEMA(Item, _id, ownerId, itemName, complexity)
Configuração do App Services
Based on the above example object model, Device Sync is configured with the following queryable fields:
_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:
{ "roles": [ { "name": "readOwnWriteOwn", "apply_when": {}, "document_filters": { "write": { "ownerId": "%%user.id" }, "read": { "ownerId": "%%user.id" } }, "read": true, "write": true, "insert": true, "delete": true, "search": true } ] }
Qualquer objeto na collection Atlas em que o ownerId
não corresponda ao user.identifier()
do usuário conectado não pode ser sincronizado com esse Realm.
Modelo de dados Realm e configuração do cliente
The examples on this page use the following synced realm configuration with this sync query and object model:
auto appConfig = realm::App::configuration(); appConfig.app_id = APP_ID; auto app = realm::App(appConfig); auto user = app.login(realm::App::credentials::anonymous()).get(); auto dbConfig = user.flexible_sync_configuration(); auto syncRealm = realm::db(dbConfig); // Add subscription auto subscriptionUpdateSuccess = syncRealm.subscriptions() .update([](realm::mutable_sync_subscription_set &subs) { // Get Items from Atlas that match this query. // Uses the queryable field `complexity`. // Sync Item objects with complexity less than or equal to 4. subs.add<realm::Item>( "simple items", [](auto &obj) { return obj.complexity <= 4; }); }) .get();
struct Item { realm::primary_key<realm::object_id> _id{realm::object_id::generate()}; std::string ownerId; std::string itemName; int64_t complexity; }; REALM_SCHEMA(Item, _id, ownerId, itemName, complexity)
With this Sync query, any object in the Atlas collection where the
complexity
property's value is greater than 4
cannot sync to this
realm.
Escreva para um domínio sincronizado
As gravações em domínios do Flexible Sync podem se enquadrar em uma das duas categorias, dependendo se a gravação corresponde às permissões e à query de assinatura do Flexible Sync:
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: o objeto gravado não corresponde à query de assinatura ou o usuário não tem permissões suficientes para realizar a gravação. O Realm reverte a escrita ilegal com uma operação de escrita compensatória.
Dica
Se você quiser gravar um objeto que não corresponde à query, poderá abrir um Realm diferente onde o objeto corresponde à query. Como alternativa, você pode gravar o objeto em um Realm não sincronizado que não impõe permissões ou query de assinatura.
Gravações bem-sucedidas
When the write matches both user permissions e a the query subscription in the client, the Realm C++ SDK can successfully write the object to the synced realm. This object syncs with the App Services backend when the device has a network connection.
// Per the Device Sync permissions, users can only read and write data // where the `Item.ownerId` property matches their own user ID. auto simpleItem = realm::Item{.ownerId = user.identifier(), .itemName = "This item meets sync criteria", .complexity = 3}; // `simpleItem` successfully writes to the realm and syncs to Atlas // because its data matches the subscription query (complexity <= 4) // and its `ownerId` field matches the user ID. syncRealm.write([&] { syncRealm.add(std::move(simpleItem)); });
Compensação de escritas
When the write doesn't match either the query subscription or user permissions, Realm reverts the write and provides an array of compensating_write_error_info objects.
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 domínio do cliente não tem nenhum conceito de escrita "ilegal", a escrita inicialmente é bem-sucedida até que o Realm resolva o changeset 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 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.
When this occurs, you can refer to the App Services logs
or use the compensating_writes_info()
function in the client to get
additional information on the error. For more information, refer
to the Informações de erro de gravação compensatórias section on this page.
A gravação não corresponde à assinatura da query
Dada a configuração do domínio Flexible Sync detalhada acima, a tentativa de gravar esse objeto resulta em um erro de gravação compensatório porque o objeto não corresponde à assinatura da query:
// The complexity of this item is `7`. This is outside the bounds // of the subscription query, which triggers a compensating write. auto complexItem = realm::Item{._id = primaryKey, .ownerId = user.identifier(), .itemName = "Test compensating writes", .complexity = 7}; // This should trigger a compensating write error when it tries to sync // due to server-side permissions, which gets logged with the error handler. syncRealm.write([&] { syncRealm.add(std::move(complexItem)); });
Connection[2]: Session[10]: Received: ERROR "Client attempted a write that is not allowed; it has been reverted" (error_code=231, is_fatal=false, error_action=Warning)
Você verá a seguinte mensagem de erro nos registros do App Services:
Error: Client attempted a write that is not allowed; it has been reverted (ProtocolErrorCode=231) Details: { "Item": { "ObjectID(\"6557ddb0bf050934870ca0f5\")": "write to ObjectID(\"6557ddb0bf050934870ca0f5\") in table \"Item\" not allowed; object is outside of the current query view" } }
A gravação não corresponde às permissões
Dadas as permissões na configuração do Device Sync detalhadas acima, a tentativa de gravar esse objeto resulta em um erro de gravação compensatório porque a propriedade ownerId
não corresponde ao user.identifier()
do usuário conectado:
// 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, which // triggers a compensating write. auto itemWithWrongOwner = realm::Item{ .ownerId = "not the current user", .itemName = "Trigger an incorrect permissions compensating write", .complexity = 1}; syncRealm.write([&] { syncRealm.add(std::move(itemWithWrongOwner)); });
Connection[2]: Session[11]: Received: ERROR "Client attempted a write that is not allowed; it has been reverted" (error_code=231, is_fatal=false, error_action=Warning)
Você verá a seguinte mensagem de erro nos registros do App Services:
Error: Client attempted a write that is outside of permissions or query filters; it has been reverted (ProtocolErrorCode=231) Details: { "Item": { "ObjectID(\"6557ddbabf050934870ca0f8\")": "write to ObjectID(\"6557ddbabf050934870ca0f8\") in table \"Item\" was denied by write filter in role \"readOwnWriteOwn\"" } }
Informações de erro de gravação compensatórias
You can get additional information in the client about why a compensating
write occurs using the compensating_writes_info()
function, which provides an array of compensating_write_error_info
structs that contain:
O
object_name
do objeto que o cliente tentou escreverO
primary_key
do objeto específicoO
reason
para o erro de gravação compensatória
This information is the same information you can find in the App Services logs. The C++ SDK exposes this object on the client for convenience and debugging purposes.
Veja a seguir um exemplo de como você pode registrar informações sobre a compensação de erros de gravação:
auto info = receivedSyncError.compensating_writes_info(); for (auto &v : info) { std::cout << "A write was rejected with a compensating write error.\n"; std::cout << "An object of type " << v.object_name << "\n"; std::cout << "was rejected because " << v.reason << ".\n"; }
A write was rejected with a compensating write error. An object of type Item was rejected because write to ObjectID("6557ddb0bf050934870ca0f5") in table "Item" not allowed; object is outside of the current query view.
O
Item
nesta mensagem é o objetoItem
usado no modelo de objeto nesta página.O
table "Item"
refere-se à collection Atlas onde este objeto sincronizaria.The reason
object is outside of the current query view
in this message is because the query subscription was set to require the object'scomplexity
property to be less than or equal to4
. The client attempted to write an object outside of this boundary.A chave primária é o
objectId
do objeto específico que o cliente tentou escrever.
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.