Docs Menu
Docs Home
/ /
Sincronizar datos del dispositivo

Escribir datos en un dominio sincronizado - SDK de Kotlin

Al escribir datos en un reino sincronizado usando Sincronización flexible: puedes usar las mismas API que al escribir en un dominio local. Sin embargo, hay 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:

class Item : RealmObject {
@PrimaryKey
var _id: ObjectId = ObjectId()
var ownerId: String = ""
var itemName: String = ""
var complexity: Int = 0
}

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.id del usuario que inició sesión no se puede sincronizar con este reino.

Utilizando el modelo de objetos, los ejemplos configuran el ámbito sincronizado para sincronizar objetos que coincidan con esta consulta de suscripción:

val app = App.create(FLEXIBLE_APP_ID)
val user = app.login(credentials)
val flexSyncConfig = SyncConfiguration.Builder(user, setOf(Item::class))
// Add subscription
.initialSubscriptions { realm ->
add(
// Get Items from Atlas that match the Realm Query Language query.
// Uses the queryable field `complexity`.
// Query matches objects with complexity less than or equal to 4.
realm.query<Item>("complexity <= 4"),
"simple-items"
)
}
.build()
val syncRealm = Realm.open(flexSyncConfig)
syncRealm.subscriptions.waitForSynchronization()
Log.v("Successfully opened realm: ${syncRealm.configuration}")

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 el guardar coincide tanto con los permisos de usuario como con la suscripción de query en el cliente, el SDK de Realm Kotlin 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 `Item.ownerId` property matches their own user ID.
val userId = user.id
val newItem = Item().apply {
ownerId = userId
itemName = "This item meets sync criteria"
complexity = 3
}
syncRealm.write {
// `newItem` is successfully written to the realm and synced to Atlas
// because its data matches the subscription query (complexity <= 4)
// and its `ownerId` field matches the user ID.
copyToRealm(newItem)
}

Cuando la operación de guardar no coincide ni con la suscripción a la query ni con los permisos del usuario, Realm revierte la guardar y lanza una CompensatingWriteException.

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 utilizar el objeto CompensatingWriteInfo en el cliente para obtener información adicional sobre el error.

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.
val itemTooComplex = Item().apply {
ownerId = user.id
itemName = "This item is too complex"
complexity = 7
}
syncRealm.write {
copyToRealm(itemTooComplex)
}
[Session][CompensatingWrite(231)] Client attempted a write that is disallowed by permissions, or modifies an object outside the current query, and the server undid the change.

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": {
"63bdfc40f16be7b1e8c7e4b7": "write to \"63bdfc40f16be7b1e8c7e4b7\"
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.id 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.
val itemWithWrongOwner = Item().apply {
ownerId = "not the current user"
itemName = "A simple item"
complexity = 1
}
syncRealm.write {
copyToRealm(itemWithWrongOwner)
}
[Session][CompensatingWrite(231)] Client attempted a write that is disallowed by permissions, or modifies an object outside the current query, and the server undid the change.

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": {
"63bdfc40f16be7b1e8c7e4b7": "write to \"63bdfc40f16be7b1e8c7e4b7\"
in table \"Item\" was denied by write filter in role \"readOwnWriteOwn\""
}
}

Nuevo en la versión 1.9.0.

Puede obtener información adicional en el cliente sobre por qué se produce una escritura compensatoria utilizando el objeto CompensatingWriteInfo, que proporciona:

  • El objectType del objeto que el cliente intentó escribir

  • El primaryKey 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 Kotlin 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:

val syncErrorHandler = SyncSession.ErrorHandler { session, error ->
runBlocking {
if (error is CompensatingWriteException) {
error.writes.forEach { writeInfo ->
val errorMessage = """
A write was rejected with a compensating write error
The write to object type: ${writeInfo.objectType}
With primary key of: ${writeInfo.primaryKey}
Was rejected because: ${writeInfo.reason}
""".trimIndent()
Log.e(errorMessage)
}
}
}
}
A write was rejected with a compensating write error
The write to object type: Item
With primary key of: RealmAny{type=OBJECT_ID, value=BsonObjectId(649f2c38835cc0346b861b74)}
Was rejected because: write to "649f2c38835cc0346b861b74" 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.

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

  • 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 ejemplo 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, y el cliente intentó escribir un objeto fuera de este límite.

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

Gestionar suscripciones

En esta página