Esta página describe cómo consultar y leer de forma diferida objetos persistentes en una base de datos con el SDK de dispositivos Atlas para Kotlin. Esta evaluación diferida mejora la eficiencia y el rendimiento del código al gestionar grandes conjuntos de datos y consultas complejas.
Operaciones de lectura
Una operación de lectura consiste en consultar objetos de la base de datos y luego ejecutar la consulta cuando esté listo para acceder a los resultados. La sintaxis de las operaciones de lectura es la misma para bases de datos sincronizadas y no sincronizadas.
Todas las consultas se basan en el tipo de objeto. Puede consultar cualquier objeto, incluidos los incrustados, que persista en la base de datos y cuyo tipo esté incluido en el esquema de la misma.
Construya consultas utilizando el generador de consultas del SDK
RealmQuery, pasando el tipo de objeto como parámetro de tipo. Puede consultar objetos en un
Realm o instancia MutableRealm, una colección RealmResults o una colección RealmList.
Un RealmQuery básico devuelve todos los objetos del tipo especificado:
// Finds all objects of type <T> .query<T>()
Se puede refinar tu query con filtros y condiciones adicionales (por ejemplo, ordenando, agregando o limitando resultados). Puedes refinar los resultados por una o más propiedades utilizando el Lenguaje de consultas de Realm (RQL), un languaje del query basado en cadenas, en combinación con funciones de extensión de Kotlin incorporadas y métodos auxiliares proporcionados por el SDK.
// Finds all objects of type <T> that meet the filter conditions // and returns them in the specified sort order .query<T>(filter).sort(sort)
También puedes encadenar consultas mediante métodos query() adicionales. Cada añadido query() actúa como una AND condición de consulta. Y gracias a la evaluación diferida del SDK, las consultas sucesivas no requieren accesos separados a la base de datos.
// Finds all objects of type <T> that meet the first filter conditions // AND the subsequent filter conditions .query<T>(filter).query(filter)
Cuando esté listo para acceder a los datos y trabajar con los resultados devueltos, ejecute la consulta:
Utilice find() para realizar una consulta síncrona. El SDK devuelve de forma diferida una colección RealmResults, que representa todos los objetos de la base de datos que cumplen las condiciones de la consulta. En general, puede trabajar con una colección de resultados como con cualquier otra colección de Kotlin.
Usa asFlow() para realizar una consulta asincrónica. El SDK se suscribe de forma diferida a un flujo de corrutina de Kotlin que puedes recopilar e iterar o escuchar para detectar cambios.No puedes llamar
asFlow()a enMutableRealm.queryun.
Tenga en cuenta que los resultados recuperados no almacenan en memoria los objetos coincidentes de la base de datos. En su lugar, la base de datos utiliza referencias directas o punteros. Los objetos de la base de datos en una colección o flujo de resultados hacen referencia a los objetos coincidentes, que se asignan directamente a los datos del archivo de base de datos. Esto también significa que puede recorrer el gráfico de las relaciones de un objeto directamente a través de los resultados de una consulta.
Ejemplo
Ejecutar la consulta
val queryAllFrogs = realm.query<Frog>() val queryAllLiveFrogs = this.query<Frog>() // this: MutableRealm // Calling 'find()' on the query returns a RealmResults collection // Can be called on a `Realm.query()` or `MutableRealm.query()` val allFrogs: RealmResults<Frog> = queryAllFrogs.find() val allLiveFrogs: RealmResults<Frog> = queryAllLiveFrogs.find() // Calling 'asFlow()' on the query returns a ResultsChange Flow // Can ONLY be called on a `Realm.query()` val allFrogsFlow: Flow<ResultsChange<Frog>> = queryAllFrogs.asFlow()
Resultados congelados y en vivo
A diferencia de otros SDK de dispositivos Atlas, que siempre devuelven resultados en tiempo real, los resultados con el SDK de Kotlin pueden estar congelados o en tiempo real. Para obtener más información sobre la arquitectura congelada del SDK de Kotlin, consulte Arquitectura congelada - SDK de Kotlin.
Para acceder a los resultados congelados, ejecute una consulta en un dominio. Los resultados congelados no se pueden modificar y no reflejan los últimos cambios en la base de datos. Un Realm.query() no requiere una transacción de escritura.
Para acceder a resultados en tiempo real, ejecute una consulta en una instancia de MutableRealm en una transacción de escritura. Un MutableRealm representa un estado de escritura en una base de datos y solo se puede acceder a él mediante una transacción de escritura. Los resultados de una consulta MutableRealm.query están en tiempo real, pero solo son válidos en el hilo que realiza la llamada y se congelan una vez completada la transacción de escritura. Para obtener más información sobre las transacciones de escritura y el acceso MutableRealm a un, consulte Transacciones de escritura.
También puede acceder a objetos activos desde resultados congelados llamando a MutableRealm.findLatest(). Para más información, consulte la sección "Buscar la última versión de un objeto" en esta página.
Ejemplo
Acceda a resultados en vivo
// 'Realm.query()' results are always frozen val frozenResults = realm.query<Frog>("age > $0", 50).find() // 'MutableRealm.query()' results are live within the current write transaction realm.write { // this: MutableRealm val liveResults = this.query<Frog>("age > $0", 50).find()
Buscar objetos de base de datos
Para encontrar objetos almacenados dentro de una base de datos:
Pase el tipo de objeto como parámetro de tipo a query(). El tipo de objeto ya debe estar incluido en el esquema de la base de datos.
Opcionalmente, pase cualquier condición de consulta para refinar aún más los resultados:
Especifique un filtro para devolver solo los objetos que cumplan la condición. Si no especifica un filtro, el SDK devolverá todos los objetos del tipo especificado.
Puede encadenar filtros agregando métodos query() adicionales
RealmQuerya.Especifique el orden de los resultados. Dado que la base de datos no está ordenada, si no incluye un orden de clasificación, el SDK no puede garantizar que la consulta devuelva los objetos en un orden específico.
Ejecute la consulta utilizando:
find() para consultas sincrónicas. Devuelve una colección de resultados.
asFlow() para consultas asincrónicas. Se suscribe a
Flowcambios en los resultados.
Tip
Prefiera asFlow() para conjuntos de datos grandes
find()Ejecuta una consulta síncrona en el hilo desde el que se llama. Por lo tanto, evite usarfind()para conjuntos de datos grandes en el hilo de interfaz de usuario o en lógica que pueda retrasarlo.Prefiera
asFlow()para evitar un impacto negativo en el rendimiento o la interfaz de usuario.Trabaje con los resultados. Los objetos pueden estar congelados o activos, según el tipo de consulta ejecutada.
Ejemplo
Operación de lectura
// Pass the object type as <T> parameter and filter by property val findFrogs = realm.query<Frog>("age > 1") // Chain another query filter .query("owner == $0 AND name CONTAINS $1", "Jim Henson", "K") // Sort results by property .sort("age", Sort.ASCENDING) // Run the query .find() // ... work with the results
Encontrar la última versión de un objeto
Debido a la arquitectura congelada del SDK, no siempre estás trabajando con la última versión de un objeto o colección.
Para obtener una versión de un objeto o colección que refleje los últimos cambios en la base de datos, puede llamar a findLatest() desde una MutableRealm instancia. Al igual que con una MutableRealm.query() instancia, los resultados están activos,pero solo son válidos en el hilo que los llama y se congelan una vez completada la transacción de escritura.
En el siguiente ejemplo, pasamos el RealmResults de una consulta frozenFrogs existente a findLatest() para obtener la última copia activa de la colección. A continuación, modificamos los objetos ya activos dentro de la transacción de escritura:
// Open a write transaction to access the MutableRealm realm.write { // this: MutableRealm for (frog in frozenFrogs) { // Call 'findLatest()' on an earlier query's frozen results // to return the latest live objects that you can modify // within the current write transaction findLatest(frog)?.also { liveFrog -> copyToRealm(liveFrog.apply { age += 1 }) println(liveFrog.name + " is now " + liveFrog.age + " years old") } } }
Tip
Puedes comprobar si un objeto está congelado con el método isFrozen().
val isFrozen = frog.isFrozen()
Consultar todos los objetos de un tipo
Para consultar todos los objetos de un tipo específico, pase el RealmObject EmbeddedRealmObject tipo de objeto o como parámetro de tipo a query() sin ningún argumento de consulta. El SDK devuelve todos los objetos del tipo especificado.
Nota
No se pueden leer objetos asimétricos
No se pueden leer objetos asimétricos, ya que son objetos especiales de solo escritura que no persisten en la base de datos. Para obtener información sobre cómo usar objetos asimétricos en su aplicación, consulte Transmitir datos a Atlas - SDK de Kotlin.
En el siguiente ejemplo, consultamos todos los RealmObject objetos del tipo Frog:
// Query all Frog objects in the database val queryAllFrogs = realm.query<Frog>() val allFrogs = queryAllFrogs.find()
En el siguiente ejemplo, consultamos todos los EmbeddedRealmObject objetos del tipo EmbeddedAddress:
val queryAllEmbeddedAddresses = realm.query<EmbeddedAddress>() val allEmbeddedAddresses = queryAllEmbeddedAddresses.find()
También puede consultar un objeto incrustado a través de su objeto principal. Para obtener más información, consulte la sección "Filtrar por propiedad de objeto incrustado" en esta página.
Tip
Una vez que encuentre un objeto incrustado, puede usar el método EmbeddedRealmObject.parent() para acceder a su padre:
val getParent = embeddedObject.parent<Contact>()
Consultar un solo objeto
Para encontrar un objeto de un tipo específico, ejecute first() en la consulta. Al ejecutar la consulta, el SDK devuelve el primer objeto que cumple las condiciones null o.
En el siguiente ejemplo, consultamos un tipo de objeto Frog y devolvemos el primer objeto:
val querySingleFrog = realm.query<Frog>().first() val singleFrog = querySingleFrog.find() if (singleFrog != null) { println("${singleFrog.name} is a frog.") } else { println("No frogs found.") }
Filtrar por propiedad
Puede filtrar una consulta por cualquier propiedad del tipo de objeto que persista en la base de datos. Esto incluye las propiedades secundarias, a las que puede hacer referencia mediante la notación de puntos.
Para filtrar por propiedad, puede usar filtros y operadores de Realm Query Language (RQL), los métodos de extensión integrados de Kotlin o los métodos de conveniencia del SDK, o una combinación de ellos. Para obtener información sobre todos los operadores y la sintaxis de RQL compatibles actualmente, consulte la documentación de referencia de Realm Query Language.
En el siguiente ejemplo, consultamos un tipo de objeto Frog y filtramos por la propiedad name:
val filterByProperty = realm.query<Frog>("name == $0", "Kermit") val frogsNamedKermit = filterByProperty.find()
Filtrar por clave principal
Las claves primarias son identificadores únicos para los objetos en una base de datos, lo que las hace útiles para consultar objetos específicos.
Para filtrar por una clave principal específica, pase el tipo de objeto como parámetro de tipo y consulte el campo de clave principal para obtener el valor deseado.
En el siguiente ejemplo, consultamos un objeto Frog y filtramos por la propiedad de clave principal _id:
val filterByPrimaryKey = realm.query<Frog>("_id == $0", PRIMARY_KEY_VALUE) val findPrimaryKey = filterByPrimaryKey.find().first()
Tip
La sincronización del dispositivo siempre utiliza _id como clave principal
Si usa Atlas Device Sync, siempre puede realizar consultas por el campo de clave _id principal. Esto se debe a que el modelo de datos de Device Sync requiere que los objetos tengan una clave principal _id llamada. Para obtener más información, consulte Datos de modelo con Device Sync - SDK de Kotlin.
Filtrar por propiedad de objeto incrustado
Los objetos incrustados actúan como datos anidados dentro de un único objeto principal específico. Puede consultar un objeto incrustado directamente o como una propiedad de su objeto principal. Para obtener información sobre cómo consultar un objeto incrustado directamente, consulte la sección "Consultar todos los objetos de un tipo" en esta página.
Para encontrar un objeto incrustado a través de su objeto padre, pasa el tipo de objeto Realm del padre como un parámetro de tipo y filtra por la propiedad del objeto incrustado usando la notación de puntos.
En el siguiente ejemplo, tenemos un objeto principal Contact que contiene una propiedad de objeto incrustada llamada address. Consultamos el tipo de objeto Contact con la propiedad address.street del objeto incrustado:
// Use dot notation to access the embedded object properties as if it // were in a regular nested object val filterEmbeddedObjectProperty = realm.query<Contact>("address.street == '123 Pond St'") // You can also access properties nested within the embedded object val queryNestedProperty = realm.query<Contact>() .query("address.propertyOwner.name == $0", "Mr. Frog")
Filtrar por propiedad RealmAny (mixta)
Una propiedad RealmAny (Mixta) representa un valor polimórfico que puede contener cualquiera de los tipos de datos admitidos en un momento dado. Puede consultar una RealmAny propiedad de la misma forma que cualquier otra propiedad.
En el siguiente ejemplo, consultamos una propiedad RealmAny llamada favoriteThing para una rana con una cosa favorita de tipo Int:
val filterByRealmAnyInt = realm.query<Frog>("favoriteThing.@type == 'int'") val findFrog = filterByRealmAnyInt.find().first()
A diferencia de otras propiedades, debe extraer el valor almacenado de una propiedad RealmAny antes de poder trabajar con ella. Para extraer el valor, utilice el método getter del SDK para el tipo almacenado. Si utiliza un getter incorrecto para el tipo, el SDK generará una excepción.
Una práctica recomendada es usar una expresión condicional para obtener el tipo almacenado actualmente con RealmAny.type() y luego extraer el valor según el tipo. Para obtener una lista completa de los métodos getter, consulte la referencia de la API de RealmAny.
En el siguiente ejemplo, extraemos el valor usando RealmAny.asInt() ya que sabemos que lo favorito de la rana devuelta es un Int valor de tipo:
val frogsFavoriteThing = findFrog.favoriteThing // Int // Using the correct getter method returns the value val frogsFavoriteNumber = frogsFavoriteThing?.asInt() println("${findFrog.name} likes the number $frogsFavoriteNumber")
Tip
Manejar el polimorfismo con expresiones condicionales
Utilice una expresión condicional when para manejar la posible clase de valor interno de una propiedad RealmAny dada:
// Handle possible types with a 'when' statement frogsFavoriteThings.forEach { realmAny -> if (realmAny != null) { when (realmAny.type) { RealmAny.Type.INT -> { val intValue = realmAny.asInt() // Do something with intValue ... } RealmAny.Type.STRING -> { val stringValue = realmAny.asString() // Do something with stringValue ... } RealmAny.Type.OBJECT -> { val objectValue = realmAny.asRealmObject(Frog::class) // Do something with objectValue ... } // Handle other possible types... else -> { // Debug or perform a default action for unhandled types Log.d("Unhandled type: ${realmAny.type}") } } } }
Una vez que tenga el valor almacenado actualmente, puede trabajar con él de la misma manera que lo haría con otro valor de ese tipo.
Nota
ByteLos valores Char, Int, Long y Short se convierten internamente a valores int64_t. Tenga esto en cuenta al comparar, ordenar o agregar valores RealmAny de estos tipos.
Filtrar por propiedad reasignada
Si su modelo de datos incluye nombres de propiedades reasignados, puede filtrar tanto por el nombre de propiedad Kotlin utilizado en su código como por el nombre de propiedad reasignado que persiste en la base de datos.
En el siguiente ejemplo, el objeto Frog tiene una propiedad denominada species en el código que se reasigna a latin_name en la base de datos:
var species: String? = null // Remapped property
En la base de datos, podemos filtrar por nombre de propiedad y devolver los mismos resultados:
val filterByKotlinName = realm.query<Frog>("species == $0", "Muppetarium Amphibius") val findSpecies = filterByKotlinName.find().first() val filterByRemappedName = realm.query<Frog>("latin_name == $0", "Muppetarium Amphibius") val find_latin_name = filterByRemappedName.find().first() // Both queries return the same object assertEquals(findSpecies, find_latin_name)
Filtrar por propiedad de búsqueda de texto completo (FTS)
Cambiado en la 1.11.0 versión: Compatibilidad con búsquedas con comodines de prefijo
Si su modelo de datos incluye una propiedad de índice de búsqueda de texto completo (FTS), puede filtrar por la propiedad con el TEXT predicado. Un tokenizador convierte las palabras de la consulta en tokens mediante las siguientes reglas:
Los tokens solo pueden contener caracteres ASCII y el suplemento latino1 (idiomas occidentales). Todos los demás caracteres se consideran espacios en blanco.
Las palabras separadas por un guion (
-) se dividen en dos tokens. Por ejemplo,full-textse divide enfullytext.Los tokens no distinguen entre mayúsculas y minúsculas ni entre signos diacríticos.
Puede buscar una palabra o frase completa o limitar sus resultados con los siguientes caracteres:
Excluya los resultados de una palabra colocando el carácter
-delante de ella. Por ejemplo,fiction -scienceincluiría todos los resultados de búsqueda defictiony excluiría aquellos que incluyan la palabrascience.En la versión y posteriores del SDK de Kotlin,1.11.0 se pueden especificar prefijos colocando el
*carácter al final de una palabra. Por ejemplo,fict*incluiría todos los resultados de búsquedafictiondefictitiousy. (Actualmente, el SDK de Kotlin no admite búsquedas de sufijos).
El SDK devuelve una coincidencia booleana para la consulta especificada, en lugar de una coincidencia basada en relevancia.
En el siguiente ejemplo, el tipo de objeto Frog tiene una propiedad de índice FTS llamada physicalDescription por la que podemos filtrar para encontrar diferentes tipos de ranas:
// Filter by FTS property value using 'TEXT' // Find all frogs with "green" in the physical description val onlyGreenFrogs = realm.query<Frog>("physicalDescription TEXT $0", "green").find() // Find all frogs with "green" but not "small" in the physical description val onlyBigGreenFrogs = realm.query<Frog>("physicalDescription TEXT $0", "green -small").find() // Find all frogs with "muppet-" and "rain-" in the physical description val muppetsInTheRain = realm.query<Frog>("physicalDescription TEXT $0", "muppet* rain*").find()
Filtrar por propiedad de colección (lista, conjunto, diccionario)
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:
RealmListRealmSetRealmDictionary
Puedes consultar estas propiedades de colección de la misma forma que cualquier otra propiedad con RQL. También puedes usar las funciones de colección integradas de Kotlin para filtrar, ordenar e iterar los resultados.
Lista de reinos
Puedes consultar e iterar a través de una propiedad RealmList como lo harías con una Lista de Kotlin
En el siguiente ejemplo, consultamos una propiedad RealmList llamada favoritePonds:
// Find frogs with a favorite pond val allFrogs = query<Frog>().find() val frogsWithFavoritePond = allFrogs.query("favoritePonds.@size > $0", 0).find() // Check if the list contains a value for (frog in frogsWithFavoritePond) { val likesBigPond = frog.favoritePonds.any { pond -> pond.name == "Big Pond" } if (likesBigPond) { Log.v("${frog.name} likes Big Pond") } else { Log.v("${frog.name} does not like Big Pond") } }
Conjunto de reinos
Puede consultar e iterar a través de una propiedad RealmSet como lo haría con un conjunto Kotlin.
En el siguiente ejemplo, consultamos una propiedad RealmSet llamada favoriteSnacks:
// Find frogs with flies and crickets as a favorite snack val filterBySnackSet = query<RealmSet_Frog>("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets") val potentialFrogs = filterBySnackSet.find() // Check if the set contains a value val frogsThatLikeWorms = potentialFrogs.filter { frog -> val requiredSnacks = query<RealmSet_Snack>("name == $0", "Worms") frog.favoriteSnacks.contains(requiredSnacks.find().first()) } for (frog in frogsThatLikeWorms) { Log.v("${frog.name} likes both Flies, Worms, and Crickets") }
Diccionario del reino
Puede consultar e iterar a través de una propiedad RealmDictionary como lo haría con un mapa Kotlin.
En el siguiente ejemplo, consultamos una propiedad RealmDictionary llamada favoritePondsByForest, que asigna una clave String (bosque) a un valor String (estanque):
// Find frogs who have forests with favorite ponds val frogs = realm.query<Frog>().find() val frogsWithFavoritePonds = frogs.query("favoritePondsByForest.@count > $0", 1).find() val thisFrog = frogsWithFavoritePonds.first() // Iterate through the map and log each key-value pair for (forestName in thisFrog.favoritePondsByForest.keys) { val pondName = thisFrog.favoritePondsByForest[forestName] Log.v("Forest: $forestName, Pond: $pondName") } // Check if the dictionary contains a key if (thisFrog.favoritePondsByForest.containsKey("Hundred Acre Wood")) { Log.v("${thisFrog.name}'s favorite pond in Hundred Acre Wood is ${thisFrog.favoritePondsByForest["Hundred Acre Wood"]}") } // Check if the dictionary contains a value if (thisFrog.favoritePondsByForest.containsValue("Picnic Pond")) { Log.v("${thisFrog.name} lists Picnic Pond as a favorite pond") }
Filtrar por propiedad de relación
Dependiendo de cómo defina su tipo de objeto, podría tener propiedades que hagan referencia a otro objeto de la base de datos. Esta puede ser una relación de uno a muchos o inversa.
Para obtener información sobre cómo filtrar por propiedades de relación que hacen referencia a un objeto incrustado, consulte la sección Filtrar por propiedad de objeto incrustado en esta página.
Relaciones de uno a uno
Una propiedad de relación "a uno" se asigna a una sola instancia de otro tipo de objeto. Puede filtrar por la propiedad de relación mediante la notación de puntos, de la misma forma que lo haría con un objeto anidado.
En el siguiente ejemplo, el tipo de objeto Frog tiene una propiedad llamada favoritePond de tipo Pond:
// Find frogs who have a favorite pond val allFrogs = query<Frog>().find() val frogsWithFavoritePond = allFrogs.query("favoritePond.@count == $0", 1).find() // Iterate through the results for (frog in frogsWithFavoritePond) { Log.v("${frog.name} likes ${frog.favoritePond?.name}") }
Relaciones de demasiadas
Las propiedades derelaciones de muchos son colecciones (una RealmList o un RealmSet) de otro tipo de objeto. Puede filtrar e iterar por la propiedad de relación como lo haría con cualquier otra propiedad de colección.
En el siguiente ejemplo, el tipo de objeto Forest tiene una propiedad llamada nearbyPonds que es un RealmList de tipo Pond:
// Find all forests with at least one nearby pond val allForests = query<Forest>().find() val forestsWithPonds = allForests.query("nearbyPonds.@count > $0", 0).find() // Iterate through the results for (forest in forestsWithPonds) { val bigPond = query<Pond>("name == $0", "Big Pond").find().first() if (forest.nearbyPonds.contains(bigPond)) { Log.v("${forest.name} has a nearby pond named ${bigPond.name}") } else { Log.v("${forest.name} does not have a big pond nearby") } }
Relaciones inversas
A diferencia de las relaciones a uno y a muchos, una relación inversa crea automáticamente un vínculo de retroceso entre los objetos padre e hijo. Esto significa que siempre se pueden realizar consultas tanto al padre como al hijo. También se puede usar la sintaxis específica de RQL para consultar el vínculo de retroceso (para más información, consulte Consultas de vínculo de retroceso).
En el siguiente ejemplo, un objeto padre de tipo User tiene una relación inversa con un objeto hijo de tipo Post. Podemos consultar la relación User.posts del objeto padre ("El usuario tiene muchas publicaciones"), así como la relación inversa Post.user ("La publicación pertenece al usuario"):
// Query the parent object val filterByUserName = query<User>("name == $0", "Kermit") val kermit = filterByUserName.find().first() // Use dot notation to access child objects val myFirstPost = kermit.posts[0] // Iterate through the backlink collection property kermit.posts.forEach { post -> Log.v("${kermit.name}'s Post: ${post.date} - ${post.title}") } // Filter posts through the parent's backlink property // using `@links.<ObjectType>.<PropertyName>` syntax val oldPostsByKermit = realm.query<Post>("date < $0", today) .query("@links.User.posts.name == $0", "Kermit") .find() // Query the child object to access the parent val post1 = query<Post>("title == $0", "Forest Life").find().first() val post2 = query<Post>("title == $0", "Top Ponds of the Year!").find().first() val parent = post1.user.first()
Importante
Consulta de relaciones inversas mediante nombres de clases reasignados
Si la propiedad de relación inversa es un tipo de objeto con un nombre de clase reasignado (persistente),debe usar el nombre de clase reasignado en la consulta RQL sin procesar.
class User : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" var posts: RealmList<Post> = realmListOf() }
// Filter by the remapped object type name // using `@links.<RemappedObjectType>.<PropertyName>` syntax val postsByKermit = realm.query<Post>() .query("@links.Blog_Author.posts.name == $0", "Kermit") .find()
Consultar datos geoespaciales
Nuevo en la versión 1.11.0.
La versión 1.11.0 y posteriores del SDK de Kotlin agregan API geoespaciales experimentales que admiten consultas con datos geoespaciales.
Nota
Para conservar datos geoespaciales, debe definir una clase integrada personalizada compatible con GeoJSON en su modelo de datos. Para obtener más información sobre los requisitos, consulte Conservar datos geoespaciales.
Los datos geoespaciales se almacenan como un par de latitud/longitud en la propiedad coordinates de un objeto incrustado personalizado. Una consulta geoespacial comprueba si el punto definido por la propiedad coordinates se encuentra dentro del límite de una forma geoespacial definida.
El SDK es compatible con las siguientes formas geoespaciales:
GeoCircle: definido por un centroGeoPointy un radioDistanceGeoBox: definido por dos coordenadasGeoPointque representan las esquinas suroeste y noreste del cuadroGeoPolygon: definido por un conjunto de al menos 4GeoPointcoordenadas que representan una forma cerrada. Esta forma puede contener huecos que representan límites exclusivos dentro de los límites del polígono definido.
Para obtener más información sobre las formas geoespaciales y cómo definirlas, consulte Datos geoespaciales - SDK de Kotlin.
Para query datos geoespaciales:
Crea un objeto que contenga los datos geoespaciales integrados.
Define la forma geoespacial para establecer el límite de la consulta.
Consulta con el operador RQL
GEOWITHIN. Este método toma la propiedadcoordinatesde su objeto incrustado compatible con GeoJSON y comprueba si ese punto está dentro de los límites de una forma definida. La sintaxis es la misma, independientemente de la forma geoespacial.
En el siguiente ejemplo, queremos consultar datos geoespaciales almacenados en un objeto Company mediante su propiedad location incrustada. Creamos dos objetos GeoCircle para definir el límite de la consulta:
val circle1 = GeoCircle.create( center = GeoPoint.create(47.8, -122.6), radius = Distance.fromKilometers(44.4) ) val circle2 = GeoCircle.create( center = GeoPoint.create(47.3, -121.9), radius = Distance.fromDegrees(0.25) )
Luego consultamos cualquier objeto Company con un location contenido dentro de los límites GeoCircle definidos:
val companiesInLargeCircle = realm.query<Company>("location GEOWITHIN $circle1").find() println("Companies in large circle: ${companiesInLargeCircle.size}") val companiesInSmallCircle = realm.query<Company>("location GEOWITHIN $circle2").find() println("Companies in small circle: ${companiesInSmallCircle.size}")
Companies in large circle: 1 Companies in small circle: 0

Ordenar y limitar resultados
Para garantizar que los resultados se devuelvan como se espera, puede especificar un orden de clasificación y condiciones de límite utilizando los operadores RQL Sort, Limit y Distinct, uno de los siguientes métodos de conveniencia del SDK o una combinación de ambos:
Importante
El orden importa
Independientemente de si se utilizan métodos RQL o de conveniencia, el SDK ejecuta cada solicitud en el orden en que se añade a la consulta. Esto puede afectar los resultados devueltos. Por ejemplo, ordenar una consulta antes de limitarla puede generar resultados muy diferentes a ordenarla después de limitarla.
En el siguiente ejemplo, ordenamos y limitamos utilizando solo métodos de conveniencia, solo RQL y luego una combinación de ambos para devolver los mismos resultados:
// Query for all frogs owned by Jim Henson, then: // 1. Sort results by age in descending order // 2. Limit results to only distinct names // 3. Limit results to only the first 2 objects val organizedWithMethods = realm.query<Frog>("owner == $0", "Jim Henson") .sort("age", Sort.DESCENDING) .distinct("name") .limit(2) .find() organizedWithMethods.forEach { frog -> Log.v("Method sort: ${frog.name} is ${frog.age}") } val organizedWithRql = realm.query<Frog>() .query("owner == $0 SORT(age DESC) DISTINCT(name) LIMIT(2)", "Jim Henson") .find() organizedWithRql.forEach { frog -> Log.v("RQL sort: ${frog.name} is ${frog.age}") } val organizedWithBoth = realm.query<Frog>() .query("owner == $0 SORT(age DESC)", "Jim Henson") .distinct("name") .limit(2) .find() organizedWithBoth.forEach { frog -> Log.v("Combined sort: ${frog.name} is ${frog.age}") }
Method sort: Kermit, Sr. is 100 Method sort: Kermit is 42 RQL sort: Kermit, Sr. is 100 RQL sort: Kermit is 42 Combined sort: Kermit, Sr. is 100 Combined sort: Kermit is 42
Nota
La ordenación de cadenas y las consultas sin distinción entre mayúsculas y minúsculas solo se admiten para los conjuntos de caracteres en 'Latin Basic', 'Latin Supplement', 'Latin Extended A' y 'Latin Extended B' (UTF-8 rango 0-591).
Resultados agregados
También puede agregar resultados, lo que reduce los resultados a un único valor según una propiedad numérica o un conjunto específico. Puede utilizar operadores de agregación RQL, uno de los siguientes métodos de conveniencia o una combinación de ambos:
En el siguiente ejemplo, agregamos la propiedad age de un tipo de objeto Frog:
val jimHensonsFrogs = realm.query<Frog>("owner == $0", "Jim Henson") // Find the total number of frogs owned by Jim Henson val numberOfJimsFrogs = jimHensonsFrogs.count().find() // Find the oldest frog owned by Jim Henson val maxAge = jimHensonsFrogs.max<Int>("age").find() val oldestFrog = jimHensonsFrogs.query("age == $0", maxAge).find().first()
Iterar resultados usando el flujo
Puede iterar a través de los resultados utilizando un flujo de corrutina de Kotlin.
Para convertir los resultados de una consulta en un Flow asíncrono, invoque asFlow() en la consulta. El SDK devuelve un ResultsChange Flow que puede iterar con flow.collect().
En el siguiente ejemplo, iteramos a través de un Flow de Frog objetos:
// Get a Flow of all frogs in the database val allFrogsQuery = realm.query<Frog>() val frogsFlow: Flow<ResultsChange<Frog>> = allFrogsQuery.asFlow() // Iterate through the Flow with 'collect()' val frogsObserver: Deferred<Unit> = async { frogsFlow.collect { results -> when (results) { is InitialResults<Frog> -> { for (frog in results.list) { Log.v("Frog: $frog") } } else -> { /* no-op */ } } } } // ... Later, cancel the Flow, so you can safely close the database frogsObserver.cancel() realm.close()
Tip
Suscríbete a los flujos para escuchar los cambios
Tras generar un a Flow partir de una consulta, puedes registrar un controlador de notificaciones para detectar cambios en ResultsChanges el. Para más información, consulta React to Changes - Kotlin SDK.