Docs Menu
Docs Home
/ /
Leer y escribir datos

Actualizar objetos de Realm - SDK de Kotlin

Esta página describe cómo actualizar un objeto Realm existente en un realm local o sincronizado mediante el SDK de Kotlin. Para obtener más información sobre la creación de objetos en un realm, consulte Crear objetos Realm - SDK de Kotlin.

Realm admite operaciones de actualización y upsert en objetos de Realm y objetos incrustados. Una operación upsert inserta una nueva instancia de un objeto o actualiza un objeto existente que cumple ciertos criterios. Para obtener más información, consulte Insertar una sección de objeto de reino en esta página.

No puedes actualizar objetos asimétricos. Esto se debe a que los objetos asimétricos son objetos especiales de solo escritura que no persisten en el realm. Para obtener información sobre cómo utilizar objetos asimétricos en tu aplicación, consulta Stream Data to Atlas - Kotlin SDK.

Nota

Escribir en un reino sincronizado

La sintaxis para actualizar un objeto en un dominio es la misma para un dominio local o sincronizado. Sin embargo, existen consideraciones adicionales que determinan si la operación de escritura en un dominio sincronizado se realiza correctamente. Para obtener más información, consulte Escribir datos en un dominio sincronizado - SDK de Kotlin.

Todas las operaciones que modifican un dominio, incluidas las de actualización y upsert, deben realizarse dentro de una transacción de escritura. Las transacciones de escritura se pasan al método write() o writeBlocking() del dominio. Con esta devolución de llamada, se puede acceder a una instancia de MutableRealm y luego actualizar objetos dentro del dominio. Para obtener más información sobre las transacciones de escritura y cómo las gestiona Realm, consulte Transacciones de escritura.

Además, solo se pueden modificar objetos activos, a los que solo se puede acceder dentro de una transacción de escritura. Se puede convertir un objeto congelado en activo en una transacción con mutableRealm.findLatest().

Ejemplo

Convertir objeto congelado antes de modificarlo

val frozenFrog = realm.query<Frog>().find().first()
// Open a write transaction
realm.write {
// Get the live frog object with findLatest(), then update it
findLatest(frozenFrog)?.let { liveFrog ->
liveFrog.name = "Kermit"
liveFrog.age -= 1
}
}

Para modificar las propiedades de un objeto Realm o un objeto incrustado almacenado dentro de un reino:

  1. Abra una transacción de escritura con realm.write() o realm.writeBlocking().

  2. Obtenga los objetos activos consultando el ámbito mutable de la transacción para los objetos que desea modificar usando query():

    1. Especifica el tipo de objeto Realm como un parámetro de tipo pasado a query().

    2. (Opcional) Filtre el conjunto de objetos devueltos especificando una consulta. Si no incluye un filtro de consulta, se devuelven todos los objetos del tipo especificado. Para obtener más información sobre las consultas con el SDK de Kotlin, consulte Leer objetos de dominio - SDK de Kotlin.

    Importante

    Los objetos deben estar vivos

    Solo se pueden modificar objetos activos. Si la consulta se produce fuera de la transacción de escritura, debe convertir los objetos congelados en activos en la transacción con mutableRealm.findLatest().

  3. Modifique el objeto dentro de la transacción de escritura. Puede usar un bloque de aplicación. Para configurar varias propiedades a la vez. Todos los cambios se guardan automáticamente en el dominio cuando Realm confirma la transacción de escritura.

Nota

Actualización de cadenas o matrices de bytes

Dado que Realm opera con campos como un todo, no es posible actualizar directamente elementos individuales de cadenas o matrices de bytes. En su lugar, debe leer el campo completo, modificar los elementos individuales y luego volver a escribirlo en un bloque de transacción.

Para actualizar un objeto Realm, consulte el tipo mediante un filtro que devuelva el objeto específico que desea actualizar. A continuación, modifique las propiedades del objeto.

Tip

Utilice información de identificación única

Recomendamos filtrar con información de identificación única, como un valor de clave principal, para garantizar que su consulta devuelva el objeto correcto.

En el siguiente ejemplo, consultamos un objeto Frog por clave primaria, luego actualizamos las propiedades name y age:

// Query and update a realm object in a single write transaction
realm.write {
val liveFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first()
liveFrog.name = "Michigan J. Frog"
liveFrog.age += 1
}

Puede actualizar un objeto incrustado modificando propiedades individuales o sobrescribiendo todo el objeto incrustado.

Tip

Acceder a objetos incrustados con notación de puntos

Puede usar la notación de puntos para acceder a las propiedades de los objetos incrustados como si se tratara de un objeto anidado normal. Para obtener más información, consulte Filtrar por propiedad de objeto incrustado.

Para actualizar una o más propiedades en un objeto incrustado, obtenga el objeto principal o incrustado y reasigne las propiedades del objeto incrustado en una transacción de escritura.

En el siguiente ejemplo, tenemos un objeto Contact que contiene un objeto EmbeddedAddress incrustado. Actualizamos las propiedades del objeto incrustado mediante varias operaciones:

// Modify embedded object properties in a write transaction
realm.write {
// Fetch the objects
val addressToUpdate = findLatest(address) ?: error("Cannot find latest version of embedded object")
val contactToUpdate = findLatest(contact) ?: error("Cannot find latest version of parent object")
// Update a single embedded object property directly
addressToUpdate.street = "100 10th St N"
// Update multiple properties
addressToUpdate.apply {
street = "202 Coconut Court"
city = "Los Angeles"
state = "CA"
postalCode = "90210"
}
// Update property through the parent object
contactToUpdate.address?.state = "NY"
}

Para sobrescribir completamente un objeto incrustado, asigne una nueva instancia del objeto incrustado a la propiedad principal en una transacción de escritura. Esto elimina el objeto incrustado existente.

En el siguiente ejemplo, tenemos un objeto Contact que contiene un objeto EmbeddedAddress incrustado. Definimos un nuevo objeto EmbeddedAddress y lo asignamos a la propiedad principal:

realm.write {
val parentObject = query<Contact>("_id == $0", PRIMARY_KEY_VALUE).find().first()
val newAddress = EmbeddedAddress().apply {
propertyOwner = Contact().apply { name = "Michigan J. Frog" }
street = "456 Lily Pad Ln"
country = EmbeddedCountry().apply { name = "Canada" }
}
// Overwrite the embedded object with the new instance (deletes the existing object)
parentObject.address = newAddress
}

También puedes actualizar varios objetos en un reino:

  1. Consulta un reino para una colección de objetos con realm.query().

  2. Abra una transacción de escritura con realm.write() o realm.writeBlocking().

  3. Actualizar elementos del conjunto de RealmResults devueltos por la consulta.

val tadpoles = realm.query<Frog>("age <= $0", 2)
for (tadpole in tadpoles.find()) {
realm.write {
findLatest(tadpole)?.name = tadpole.name + " Jr."
}
}

Dependiendo de cómo defina su tipo de objeto, es posible que tenga propiedades que sean tipos especiales específicos del reino.

Puede utilizar las siguientes funciones de la API de Realm para actualizar un valor de propiedad MutableRealmInt:

  • increment()

  • decrement()

  • set()

Estos métodos devuelven la propiedad MutableRealmInt con un valor mutado.

Tip

Utilice el operador set() con precaución

El operador set() sobrescribe cualquier llamada anterior a increment() o decrement(). No recomendamos combinar set() con increment() o decrement(), a menos que el conteo difuso sea aceptable para su caso.

Además de las funciones de la API de Realm, también puedes utilizar el siguiente conjunto de operadores y funciones infijas similares a las proporcionadas por la biblioteca estándar de Kotlin Longpara:

  • Operadores de prefijo unarios: unaryPlus, unaryMinus

  • Operadores de incremento y decremento: inc, dec (no debe confundirse con increment y decrement)

  • Operadores aritméticos: plus, minus, times, div, rem

  • Operadores de igualdad: equals

  • Operadores de comparación: compareTo

  • Funciones bit a bit: shl, shr, ushr, and, or, xor, inv

Sin embargo, estos operadores y funciones infijas no modifican la instancia en la que se invocan. En su lugar, devuelven una nueva instancia no administrada con el resultado de la operación.

Importante

Sólo los métodos de reino dan como resultado un valor mutado

Las únicas operaciones que generan un valor mutado son las funciones de la API de Realm: increment, decrement y set. Todas las demás operaciones (incluidas inc y dec) devuelven una instancia no administrada con un nuevo valor.

En el siguiente ejemplo, actualizamos una propiedad MutableRealmInt con operaciones increment(), decrement() y set():

// Open a write transaction
realm.write {
// Get the live object
val frog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first()
val counter: MutableRealmInt? = frog.fliesEaten
counter?.get() // 1
// Increment the value of the MutableRealmInt property
// ** Note use of decrement() with negative value **
counter?.increment(0) // 1
counter?.increment(5) // 6
counter?.decrement(-2) // 8
// Decrement the value of the MutableRealmInt property
// ** Note use of increment() with negative value **
counter?.decrement(0) // 8
counter?.decrement(2) // 6
counter?.increment(-1) // 5
// Set the value of the MutableRealmInt property
// ** Use set() with caution **
counter?.set(0)// 0
}

Las propiedadesRealmAny son inmutables. Para actualizar un RealmAny valor, debe crear una nueva instancia de la propiedad con el valor y tipo deseados. Para obtener más información sobre cómo agregar RealmAny propiedades, consulte Crear una propiedad RealmAny (Mixta).

Además,debe conocer el tipo almacenado para extraer el valor de una RealmAny propiedad. Si llama a un método getter con el tipo incorrecto, Realm genera una excepción.

Tip

Manejar el polimorfismo con expresiones condicionales

Dado que debe conocer el tipo almacenado para extraer su valor, recomendamos utilizar una expresión when para manejar el tipo RealmAny y su posible clase de valor interno.

val favoriteThings = frog.favoriteThings
when (favoriteThings.type) {
INT -> rating(favoriteThings.asInteger())
STRING -> description(favoriteThings.asString())
BYTE_ARRAY -> image(favoriteThings.asByteArray())
// Handle other possible types...
else -> {
// Debug or a perform default action
Log.d("ExampleHandler", "Unhandled type: ${favoriteThings.type}")
}
}

En el siguiente ejemplo, actualizamos un objeto Frog que contiene una lista de propiedades RealmAny creando nuevas instancias de cada elemento de la lista:

// Find favoriteThing that is an Int
// Convert the value to Double and update the favoriteThing property
realm.write {
val kermit = query<Frog>().find().first()
val realmAny: RealmList<RealmAny?> = kermit.favoriteThings
for (i in realmAny.indices) {
val thing = realmAny[i]
if (thing?.type == RealmAny.Type.INT) {
val intValue = thing.asInt()
val doubleValue = intValue.toDouble()
realmAny[i] = RealmAny.create(doubleValue)
}
}
}
// Overwrite all existing favoriteThing properties
// ** Null clears the property value **
realm.write {
val frog = query<Frog>().find().first()
val realmAny: RealmList<RealmAny?> = frog.favoriteThings
realmAny[0] = RealmAny.create("sunshine")
realmAny[1] = RealmAny.create(Frog().apply { name = "Kermit Sr." })
realmAny[2] = null
}

Nota

Borrar un valor de propiedad RealmAny con null

Puede asignar null directamente a una propiedad RealmAny para eliminar el valor actual.

Dependiendo de cómo defina su tipo de objeto, es posible que tenga propiedades que estén definidas como uno de los siguientes tipos de colección compatibles:

  • RealmList

  • RealmSet

  • RealmDictionary

Las colecciones son mutables y están respaldadas por sus correspondientes clases integradas de Kotlin. Puedes añadir y eliminar elementos de una colección en una transacción de escritura.

Tip

Escuchar los cambios en una colección

Puede registrar un controlador de notificaciones para detectar cambios. Para obtener más información, consulte Registrar un controlador de notificaciones de cambios de colección.

Puedes actualizar elementos en una RealmList como lo harías en una MutableList de Kotlin.

En el siguiente ejemplo, actualizamos RealmList elementos para un objeto Frog existente:

realm.write {
// Get the live object
val realmList = query<Frog>("name = $0", "Kermit").first().find()!!.favoritePonds
realmList[0].name = "Picnic Pond"
realmList.set(1, Pond().apply { name = "Big Pond" })
}

Para obtener más información sobre cómo agregar y eliminar RealmList elementos, consulte Crear una RealmList y Eliminar elementos de una RealmList.

Puede agregar, actualizar y eliminar elementos en un RealmSet como lo haría en un MutableSet de Kotlin.

En el siguiente ejemplo, iteramos y actualizamos elementos RealmSet para objetos Frog existentes:

// Find a frog in the realm
val kermit = realm.query<Frog>("name = $0", "Kermit").find().first()
val realmSet = kermit.favoriteSnacks
// Update the name of each snack in the set
for (snack in realmSet) {
realm.write {
findLatest(snack)?.name = snack.name.uppercase()
}
}
realm.write {
// Find all frogs who like rain
val frogsWhoLikeRain = realm.query<Frog>("favoriteWeather CONTAINS $0", "rain").find()
// Add thunderstorms to their favoriteWeather set
for (frog in frogsWhoLikeRain) {
val latestFrog = findLatest(frog)
latestFrog?.favoriteWeather?.add("thunderstorms")
}
}

Para obtener más información sobre cómo agregar y eliminar RealmSet elementos, consulte Crear una propiedad RealmSet y Eliminar elementos de un RealmSet.

Puede actualizar claves y valores en un RealmDictionary como lo haría en un Kotlin MutableMap.

En el siguiente ejemplo, actualizamos un RealmDictionary

// Find frogs who have forests with favorite ponds
val thisFrog = realm.query<RealmDictionary_Frog>("favoritePondsByForest.@count > 1").find().first()
// Update the value for a key if it exists
if (thisFrog.favoritePondsByForest.containsKey("Hundred Acre Wood")) {
realm.write {
findLatest(thisFrog)?.favoritePondsByForest?.set("Lothlorien", "Lily Pad Pond")
}
}
// Add a new key-value pair
realm.write {
findLatest(thisFrog)?.favoritePondsByForest?.put("Sherwood Forest", "Miller Pond")
}

Para obtener más información sobre cómo agregar y eliminar RealmDictionary entradas, consulte Crear una propiedad de diccionario y Eliminar claves/valores de diccionario.

Dependiendo de cómo defina su tipo de objeto, podría tener propiedades que hagan referencia a otro objeto Realm. Esta puede ser una relación de uno a uno, de muchos a muchos o inversa.

También puede incrustar un objeto Realm directamente dentro de otro para crear una estructura de datos anidada de EmbeddedRealmObject tipo. Para obtener más información, consulte la sección "Actualizar un objeto incrustado" en esta página.

Puede actualizar las relaciones entre objetos en un reino modificando las propiedades que definen la relación de la misma manera que actualizaría cualquier otra propiedad.

En el siguiente ejemplo, tenemos un objeto Frog con una propiedad favoritePond que hace referencia a un solo objeto Pond y una propiedad bestFriend que hace referencia a otro objeto Frog:

realm.write {
val kermit = query<Frog>("name == $0", "Kermit").find().first()
// Update a property on the related object
kermit.favoritePond?.name = "Big Pond"
// Assign a new related object
val newBestFriend = Frog().apply { name = "Froggy Jr." }
kermit.bestFriend = newBestFriend
}

Puede actualizar las relaciones "de varios" de la misma manera que cualquier otra colección. Consulte la sección "Actualizar propiedades de colección" en esta página.

En el siguiente ejemplo, tenemos un objeto Forest con una propiedad frogsThatLiveHere que hace referencia a un conjunto de Frog objetos y una propiedad nearByPonds que hace referencia a una lista de Pond objetos:

realm.write {
val forest = query<Forest>().find().first()
// Update a property on a related object in the set
forest.frogsThatLiveHere.first().name = "Kermit Sr."
// Add a new related object to the list
forest.frogsThatLiveHere.add(Frog().apply { name = "Froggy Jr." })
}

Puede acceder y actualizar objetos en una relación inversa. Sin embargo,no puede modificar directamente la colección de vínculos de retroceso. En su lugar, Realm actualiza automáticamente la relación implícita al modificar cualquier objeto relacionado. Para obtener más información, consulte Definir una relación inversa.

En el siguiente ejemplo, tenemos un objeto principal User con una propiedad de vínculos de retroceso posts que hace referencia a una lista de Post objetos secundarios. Actualizamos las propiedades de los objetos principal y secundario mediante el vínculo de retroceso:

realm.write {
// Update child objects through the parent
val parent = query<User>().find().first()
parent.posts[0].title = "Forest Life Vol. 2"
parent.posts.add(Post().apply { title = "Forest Life Vol. 3" })
// Update child objects (Realm automatically updates the backlink collection)
val child = query<Post>("title == $0", "Top Ponds of the Year!").find().first()
child.title = "Top Ponds of the Year! Vol. 2"
assertEquals("Top Ponds of the Year! Vol. 2", parent.posts[1].title)
// Update the parent object through the child
child.user[0].name = "Kermit Sr."
// ** You CANNOT directly modify the backlink collection **
val readOnlyBacklink: RealmResults<User> = child.user
}

Para insertar un objeto en un reino, inserte un objeto con una clave principal usando copyToRealm(), como lo haría al crear un nuevo objeto, y pase un parámetro UpdatePolicy para especificar cómo el SDK maneja los objetos existentes con la misma clave principal:

  • UpdatePolicy.ALL:Actualizar todas las propiedades de cualquier objeto existente identificado con la misma clave principal.

  • UpdatePolicy.ERROR (Predeterminado): No permite actualizar objetos existentes y, en su lugar, genera una excepción si ya existe un objeto con la misma clave principal. Si no especifica una política de actualización, Realm la usa de forma predeterminada.

Dependiendo de la política de actualización, puede ocurrir lo siguiente:

  • Si no existe ningún objeto que coincida con la clave principal, el SDK inserta el nuevo objeto.

  • Si ya existe un objeto con la misma llave primaria, el SDK puede:

    • Actualiza todas las propiedades de cualquier objeto existente identificado con la misma clave principal. Tenga en cuenta que las propiedades se marcan como actualizadas en los detectores de cambios, incluso si la propiedad se actualizó al mismo valor.

    • Lanza una excepción que indica que ya existe un objeto en el reino.

En el siguiente ejemplo, intentamos insertar un objeto Frog con una clave principal que ya existe en el reino con UpdatePolicy.ALL y confirmamos que el objeto se insertó correctamente:

realm.write {
val existingFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first()
assertEquals(existingFrog.name, "Kermit")
// Use copyToRealm() to insert the object with the primary key
// ** UpdatePolicy determines whether to update or throw an error if object already exists**
copyToRealm(Frog().apply {
_id = PRIMARY_KEY_VALUE
name = "Wirt"
age = 4
species = "Greyfrog"
owner = "L'oric"
}, UpdatePolicy.ALL)
val upsertFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first()
assertEquals(upsertFrog.name, "Wirt")
}

Volver

Lea