Al escribir datos en un reino sincronizado usando Sincronización flexible: puedes usar las mismas API que al realizar operaciones CRUD en un dominio no sincronizado. Sin embargo, existen algunas diferencias de comportamiento que debes tener en cuenta al desarrollar tu aplicación.
When you write to a synced realm, your write operations must match both of the following:
La query de suscripción de sincronización
The permissions in your App Services App
Si intentas escribir datos que no coinciden ni con la suscripción de query ni con los permisos del usuario, Realm revierte la escritura con una operación de error no fatal llamada escritura compensatoria.
To learn more about configuring permissions for your app, see Role-based Permissions and the Device Sync Permissions Guide in the App Services documentation.
Para obtener más información sobre errores permitidos denegados, errores de guardar compensatoria y otros tipos de errores de Device Sync, consulta Errores de sincronizar en la documentación de aplicación Services.
Determining What Data Syncs
The data that you can write to a synced realm is determined by the following:
Your Device Sync configuration
Permisos en tu aplicación
La consulta de suscripción de sincronización flexible que se utiliza al abrir el reino
The examples on this page use an Atlas App Services App with the following Device Sync configuration and a client app with the following Realm SDK data model and subscriptions.
In this example, the client app uses the following object model:
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)
Configuración de servicios de aplicaciones
Basado en el modelo de objeto de ejemplo anterior, Device Sync está configurado con los siguientes campos consultables:
_id(siempre incluido)complexityownerId
The App Services App has permissions configured to let users read and write only their own data:
{ "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 } ] }
Cualquier objeto en la colección Atlas donde el ownerId no coincida con el user.identifier() del usuario que inició sesión no se puede sincronizar con este reino.
Client Data Model and Configuration
Los ejemplos en esta página utilizan la siguiente configuración Realm sincronizada con esta query de sincronización y Modelo de objeto:
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.
Write to a Synced Realm
Writes to Flexible Sync realms may broadly fall into one of two categories, depending on whether the write matches the permissions and the Flexible Sync subscription query:
Successful writes: The written object matches both the query subscription and the user's permissions. The object writes successfully to the realm, and syncs successfully to the App Services backend and other devices.
Compensating writes: The written object does not match the subscription query or the user does not have sufficient permissions to perform the write. Realm reverts the illegal write with a compensating write operation.
Tip
If you want to write an object that does not match the query subscription, you can open a different realm where the object matches the query subscription. Alternately, you could write the object to a non-synced realm that does not enforce permissions or subscription queries.
Successful Writes
Cuando la operación de guardar coincide tanto con los permisos del usuario como con la suscripción de la query en el cliente, el C++ SDK de Realm puede guardar con éxito el objeto en el realm sincronizado. Este objeto se sincroniza con el backend de aplicación Services cuando el dispositivo tiene conexión a la red.
// 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)); });
Compensating Writes
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.
In more detail, when you write data that is outside the bounds of a query subscription or does not match the user's permissions, the following occurs:
Because the client realm has no concept of "illegal" writes, the write initially succeeds until Realm resolves the changeset with the App Services backend.
Upon sync, the server applies the rules and permissions. The server determines that the user does not have authorization to perform the write.
The server sends a revert operation, called a "compensating write", back to the client.
The client's realm reverts the illegal write operation.
Any client-side writes to a given object between an illegal write to that object and the corresponding compensating write will be lost. In practice, this may look like the write succeeding, but then the object "disappears" when Realm syncs with the App Services backend and performs the compensating write.
Cuando esto ocurre, puede consultar los registros de App Services o usar la compensating_writes_info() función en el cliente para obtener más información sobre el error. Para más información, consulte la sección "Información sobre errores de escritura compensados" en esta página.
La escritura no coincide con la suscripción de consulta
Dada la configuración para el Flexible Sync realm detallada arriba, intentar escribir este objeto resulta en un error de escritura compensatoria porque el objeto no coincide con la suscripción de 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)
Verá el siguiente mensaje de error en los registros de 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" } }
Guardar no coincide con los permisos
Dados los permisos en la configuración de Device Sync detallada anteriormente, intentar guardar este objeto resulta en un error de escritura compensatoria porque la propiedad ownerId no coincide con la user.identifier() del usuario que ha iniciado sesión:
// 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)
Verá el siguiente mensaje de error en los registros de 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\"" } }
Compensating Write Error Information
Puede obtener información adicional en el cliente sobre por qué ocurre una escritura compensatoria utilizando la función compensating_writes_info(), que proporciona una matriz de compensating_write_error_info estructuras que contienen:
El
object_namedel objeto que el cliente intentó escribirThe
primary_keyof the specific objectThe
reasonfor the compensating write error
Esta información es la misma que se encuentra en los registros de App Services. El SDK de C++ expone este objeto en el cliente para mayor comodidad y para la depuración.
A continuación, se muestra un ejemplo de cómo podrías registrar información sobre errores de escritura compensatorios:
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.
El
Itemen este mensaje es elItemobjeto utilizado en el modelo de objetos de esta página.The
table "Item"refers to the Atlas collection where this object would sync.The reason
object is outside of the current query viewin this message is because the query subscription was set to require the object'scomplexityproperty to be less than or equal to4. The client attempted to write an object outside of this boundary.The primary key is the
objectIdof the specific object the client attempted to write.
Group Writes for Improved Performance
Every write transaction for a subscription set has a performance cost. If you need to make multiple updates to a Realm object during a session, consider keeping edited objects in memory until all changes are complete. This improves sync performance by only writing the complete and updated object to your realm instead of every change.