Al escribir datos en un dominio sincronizado mediante Sincronización Flexible, se pueden usar las mismas API que al escribir en un dominio local. Sin embargo, existen algunas diferencias de comportamiento que se deben tener en cuenta al desarrollar la aplicación. Para obtener más información sobre la lectura y escritura de datos en un dominio, consulte Leer y escribir datos.
Cuando escribe en un reino sincronizado, sus operaciones de escritura deben coincidir con ambos puntos siguientes:
- La consulta de suscripción de sincronización.
Si su operación de escritura no coincide con la consulta en la suscripción, la escritura se revierte con un error de escritura compensatorio no fatal (ErrorCompensatingWrite).
Para obtener más información sobre cómo compensar errores de escritura y cómo evitarlos, consulte la Sección deescrituras compensatorias.
- Los permisos en su aplicación App Services.
Si intenta escribir datos que no coinciden con la expresión de permisos, la escritura se revierte con un error de permiso denegado (no fatal). En el cliente, esto se muestra como un error (ErrorCompensatingWrite). En el servidor, puede ver más detalles sobre cómo se denegó la escritura mediante un filtro de escritura en el rol.
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.
Cómo determinar qué datos se sincronizan
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.
Configuración de servicios de aplicaciones
La sincronización del dispositivo está configurada con los siguientes campos consultables:
_id(siempre incluido)milesownerId
La aplicación Servicios de aplicaciones tiene permisos configurados para permitir a los usuarios leer y escribir solo sus propios datos:
{ "name": "owner-read-write", "apply_when": {}, "document_filters": { "read": { "ownerId": "%%user.id" }, "write": { "ownerId": "%%user.id" } }, "read": true, "write": true }
Modelo de datos del cliente y configuración
Los ejemplos de esta página utilizan el siguiente esquema:
() class _Car { ("_id") () late ObjectId id; // This is the queryable field late String ownerId; late String make; late String? model; late int? miles; }
Usando ese esquema, los ejemplos configuran el reino sincronizado para sincronizar objetos que coinciden con esta consulta de suscripción:
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();
Escribir en un reino sincronizado
Las escrituras en los dominios de sincronización flexible pueden clasificarse en dos categorías:
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: cuando el objeto escrito no coincide con la consulta de suscripción, o cuando el usuario no tiene permisos suficientes para realizar la escritura, Realm revierte la escritura ilegal.
Escrituras exitosas
Cuando la operación de escritura coincide tanto con los permisos de App Services como con la suscripción de Flexible Sync query en el cliente, el SDK de Realm Flutter puede guardar correctamente el objeto en el realm sincronizado. Este objeto se sincroniza con el backend de aplicación Services cuando el dispositivo tiene una conexión de red.
// 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); });
Escrituras compensatorias
En algunos casos, una escritura que inicialmente parece correcta es en realidad una escritura ilegal. En estos casos, el objeto escribe en la base de datos, pero cuando esta se sincroniza con el backend, Realm revierte la escritura mediante una operación de compensación de errores no fatales. Las escrituras de compensación pueden ocurrir cuando:
Las escrituras no coinciden con la suscripción de consulta: el objeto escrito coincide con los permisos del usuario, pero no coincide con la suscripción de consulta.
Guardados no coinciden con los permisos: El objeto guardado coincide con la suscripción de la query, pero no coincide con los permisos del usuario.
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:
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.
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.
El servidor envía una operación de reversión, denominada "escritura compensatoria", al cliente.
El reino del cliente revierte la operación de escritura ilegal.
Cualquier guardado realizado del lado del cliente en un objeto determinado entre un guardado ilegal y el correspondiente guardado de compensación se perderá.
En la práctica, esto puede parecer como un objeto que se escribe en el reino y luego desaparece después de que el servidor envía la escritura compensatoria al cliente.
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 registros de App Services contienen más información sobre por qué ocurre un error de escritura compensatoria.
Operaciones de escritura que no coinciden con la suscripción de query
Solo se pueden escribir objetos en un dominio de sincronización flexible si coinciden con la consulta de suscripción. Si se realiza una escritura que no coincide con la consulta de suscripción, Realm escribe inicialmente el objeto, pero luego realiza una escritura compensatoria. Esta operación no fatal revierte una escritura no válida que no coincide con la consulta de suscripción.
Si desea escribir un objeto que no coincide con la suscripción de consulta, abra un dominio diferente donde el objeto coincida con la suscripción de consulta. Como alternativa, puede escribir el objeto en un dominio local que no aplique permisos ni consultas de suscripción.
Ejemplo de código
Dada la configuración del reino sincronizado anterior, intentar escribir este objeto no coincide con la suscripción de consulta:
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);
Error del cliente
El mensaje de error en los registros del lado del cliente en este escenario es:
[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
Error de servicios de aplicaciones
El mensaje de error en los registros de aplicación Services en este escenario es:
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" } }
Escrituras que no coinciden con los permisos
Intentar escribir en el cliente también puede desencadenar un error de escritura compensatorio cuando el objeto no coincide con los permisos de escritura del lado del servidor del usuario.
En el cliente, este tipo de escritura se comporta igual que una escritura que no coincide con la suscripción de la consulta. En la práctica, puede parecer que la escritura se realizó correctamente, pero el objeto desaparece cuando Realm se sincroniza con el backend de App Services y realiza la escritura compensatoria.
Ejemplo de código
Dado los permisos en la configuración Device Sync detallados anteriormente, intentar escribir un objeto donde la propiedad ownerId no coincida con la user.id del usuario que ha iniciado sesión no es una escritura 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);
Error del cliente
El error del cliente en este escenario es el mismo que cuando intenta escribir un objeto que está fuera de los permisos de 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
Error de servicios de aplicaciones
El mensaje de error en los registros de App Services proporciona información adicional para ayudarle a determinar si se trata de un problema de permisos y no de suscripción a consultas. En este ejemplo, el mensaje de error indica que el objeto no coincide con el rol del usuario:
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\"" } }