Docs Menu
Docs Home
/ /
Sincronizar datos

Guardar datos en un Realm sincronizado - C++ SDK

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.

Cuando escribe en un reino sincronizado, sus operaciones de escritura deben coincidir con ambos puntos siguientes:

  • La consulta de suscripción de sincronización

  • Los permisos en su aplicación App Services

Si intenta escribir datos que no coinciden con la suscripción de consulta o los permisos del usuario, Realm revierte la escritura con una operación de error no fatal llamada escritura compensatoria.

Para obtener más información sobre cómo configurar permisos para su aplicación, consulte Permisos basados ​​en roles y la Guía de permisos de sincronización de dispositivos en la documentación de App Services.

Para obtener más información sobre errores de permiso denegado, compensación de errores de escritura y otros tipos de errores de sincronización de dispositivos, consulte Errores de sincronización en la documentación de App Services.

Los datos que puedes escribir en un reino sincronizado están determinados por lo siguiente:

  • Configuración de sincronización de su dispositivo

  • Permisos en tu aplicación

  • La consulta de suscripción de sincronización flexible que se utiliza al abrir el reino

Los ejemplos de esta página utilizan una aplicación Atlas App Services con la siguiente configuración de sincronización de dispositivos y una aplicación cliente con el siguiente modelo de datos y suscripciones de Realm SDK.

En este ejemplo, la aplicación cliente utiliza el siguiente modelo de objetos:

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)

Basado en el modelo de objeto de ejemplo anterior, Device Sync está configurado con los siguientes campos consultables:

  • _id (siempre incluido)

  • complexity

  • ownerId

La aplicación Servicios de aplicaciones tiene permisos configurados para permitir a los usuarios leer y escribir solo sus propios datos:

{
"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.

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)

Con esta consulta de sincronización, cualquier objeto en la colección Atlas donde el valor de la propiedad complexity sea mayor que 4 no se puede sincronizar con este reino.

Las escrituras en los dominios de Flexible Sync pueden clasificarse en dos categorías, dependiendo de si la escritura coincide con los permisos y la consulta de suscripción de Flexible Sync:

  • Escrituras correctas: El objeto escrito coincide con la suscripción de consulta y los permisos del usuario. El objeto se escribe correctamente en el dominio y se sincroniza correctamente con el backend de App Services y otros dispositivos.

  • Escrituras compensatorias: El objeto escrito no coincide con la consulta de suscripción o el usuario no tiene permisos suficientes para realizar la escritura. Realm revierte la escritura ilegal con una operación de escritura compensatoria.

Tip

Si desea escribir un objeto que no coincide con la suscripción de consulta, puede abrir un dominio diferente donde el objeto coincida con dicha suscripción. Como alternativa, puede escribir el objeto en un dominio no sincronizado que no aplique permisos ni consultas de suscripción.

Cuando la escritura coincide con los permisos del usuario y la suscripción de consulta en el cliente, el SDK de Realm C++ puede escribir correctamente el objeto en el dominio sincronizado. Este objeto se sincroniza con el backend de App Services cuando el dispositivo tiene conexión de 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)); });

Cuando la escritura no coincide con la suscripción de consulta o los permisos del usuario, Realm revierte la escritura y proporciona una matriz de objetos compensating_write_error_info.

En más detalle, cuando se escriben datos que están fuera de los límites de una suscripción de consulta o no coinciden con los permisos del usuario, ocurre lo siguiente:

  1. Debido a que el ámbito del cliente no tiene el concepto de escrituras "ilegales", la escritura inicialmente tiene éxito hasta que el ámbito resuelve el conjunto de cambios con el backend de App Services.

  2. Tras la sincronización, el servidor aplica las reglas y los permisos. El servidor determina que el usuario no tiene autorización para realizar la escritura.

  3. El servidor envía una operación de reversión, denominada "escritura compensatoria", al cliente.

  4. El reino del cliente revierte la operación de escritura ilegal.

Cualquier escritura del lado del cliente en un objeto determinado entre una escritura ilegal en ese objeto y la escritura compensatoria correspondiente se perderá. En la práctica, esto puede parecer una escritura exitosa, pero el objeto desaparece cuando Realm se sincroniza con el backend de App Services y realiza la escritura compensatoria.

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.

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

Dados los permisos en la configuración de sincronización del dispositivo detallados anteriormente, intentar escribir este objeto da como resultado un error de escritura compensatorio porque la ownerId propiedad no coincide con la user.identifier() del usuario que inició 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\""
}
}

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_name del objeto que el cliente intentó escribir

  • El primary_key del objeto específico

  • El reason para el error de escritura compensatorio

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 puede registrar información sobre la compensación de errores de escritura:

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 Item en este mensaje es el Item objeto utilizado en el modelo de objetos de esta página.

  • table "Item" hace referencia a la colección Atlas donde se sincronizaría este objeto.

  • El motivo object is outside of the current query view en este mensaje se debe a que la suscripción de consulta se configuró para requerir que la propiedad complexity del objeto sea menor o igual a 4. El cliente intentó escribir un objeto fuera de este límite.

  • La clave principal es objectId del objeto específico que el cliente intentó escribir.

Cada transacción de escritura para un conjunto de suscripciones tiene un coste de rendimiento. Si necesita realizar varias actualizaciones a un objeto de Realm durante una sesión, considere mantener los objetos editados en memoria hasta que se completen todos los cambios. Esto mejora el rendimiento de la sincronización al escribir solo el objeto completo y actualizado en su reino, en lugar de cada cambio.

Volver

Administrar suscripciones de sincronización

En esta página