Operaciones de lectura
Puedes leer los datos almacenados en Realm. El patrón estándar de acceso a datos en los SDK de Realm consiste en buscar, filtrar y ordenar objetos, en ese orden. Para obtener el máximo rendimiento de Realm a medida que tu aplicación crece y tus consultas se vuelven más complejas, diseña los patrones de acceso a datos de tu aplicación basándose en un conocimiento sólido de Realm. leer características.
Leer Características
Cuando diseña los patrones de acceso a datos de su aplicación en torno a las siguientes tres características clave de lectura en Realm, puede estar seguro de que está leyendo los datos de la manera más eficiente posible.
Los resultados no son copias
Los resultados de una consulta no son copias de sus datos: modificarlos modificará directamente los datos en el disco. Esta asignación de memoria también significa que los resultados están en tiempo real, es decir, siempre reflejan el estado actual del disco.
Los resultados son perezosos
Realm pospone la ejecución de una consulta hasta que se acceda a los resultados. Se pueden encadenar varias operaciones de filtrado y ordenación sin necesidad de procesar el estado intermedio.
Se conservan las referencias
Una ventaja del modelo de objetos de Realm es que Realm conserva automáticamente todas las relaciones de un objeto como referencias directas, de modo que puede recorrer su gráfico de relaciones directamente a través de los resultados de una consulta.
Una referencia directa, o puntero, te permite acceder directamente a las propiedades de un objeto relacionado a través de la referencia.
Otras bases de datos suelen copiar objetos del almacenamiento de la base de datos a la memoria de la aplicación cuando necesitas trabajar directamente con ellos. Debido a que los objetos de la aplicación contienen referencias directas, tienes la siguiente opción: copiar el objeto al que se hace referencia en cada referencia directa fuera de la base de datos en caso de que sea necesario, o simplemente copiar la clave externa de cada objeto y hacer query para el objeto con esa clave si se accede a él. Si eliges copiar objetos referenciados a la memoria de la aplicación, puedes usar muchos recursos para objetos a los que nunca se accede, pero si elige solo copiar la clave externa, las búsquedas de objetos referenciados pueden causar que su aplicación se vuelva lenta.
Realm evita todo esto mediante objetos activos de copia cero. Los accesos a objetos de Realm apuntan directamente al almacenamiento de la base de datos mediante mapeo de memoria, por lo que no hay distinción entre los objetos en Realm y los resultados de la consulta en la memoria de la aplicación. Gracias a esto, se pueden recorrer referencias directas en todo un reino desde cualquier resultado de consulta.
Acerca de los ejemplos de esta página
Los ejemplos de esta página utilizan el modelo de datos de una aplicación de gestión de proyectos que tiene dos tipos de objetos Realm: Project
y Task. Un Project tiene cero o más Tasks.
Vea el esquema de estas dos clases, Project y Task, a continuación:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class ProjectTask extends RealmObject { public ObjectId _id; public String name; public String assignee; public int progressMinutes; public boolean isComplete; public int priority; public String _partition; }
import org.bson.types.ObjectId; import io.realm.RealmList; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; import io.realm.annotations.RealmClass; import io.realm.annotations.Required; public class Project extends RealmObject { public ObjectId _id; public String name; public RealmList<ProjectTask> tasks = new RealmList<>(); }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class ProjectTask( var _id: ObjectId = ObjectId(), var name: String = "", var assignee: String? = null, var progressMinutes: Int = 0, var isComplete: Boolean = false, var priority: Int = 0, var _partition: String = "" ): RealmObject()
import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey import io.realm.annotations.Required import org.bson.types.ObjectId open class Project( var _id: ObjectId = ObjectId(), var name: String = "", var tasks: RealmList<ProjectTask> = RealmList(), ): RealmObject()
Leer desde el reino
Una lectura de un reino generalmente consta de los siguientes pasos:
Obtener todos los objetos de un determinado tipo del reino.
Opcionalmente, filtre los resultados utilizando el motor de consulta.
Opcionalmente, ordene los resultados.
Todas las operaciones de consulta, filtrado y ordenación devuelven una colección de resultados. Estas colecciones están en tiempo real, lo que significa que siempre contienen los resultados más recientes de la consulta asociada.
Importante
Lecturas y escrituras sincrónicas en el hilo de interfaz de usuario
De forma predeterminada, solo se puede leer o escribir en un dominio en el hilo de interfaz de usuario de la aplicación mediante transacciones asíncronas. Es decir, solo se pueden usar Realm métodos cuyo nombre termine con la palabra Async en el hilo principal de la aplicación Android, a menos que se permita explícitamente el uso de métodos síncronos.
Esta restricción existe en beneficio de los usuarios de tu aplicación: realizar operaciones de lectura y escritura en el hilo de la Interfaz de Usuario puede generar interacciones lentas o no respondidas en la Interfaz de Usuario, por lo que generalmente es mejor gestionar estas operaciones de manera asíncrona o en un hilo en segundo plano. Sin embargo, si tu aplicación requiere el uso de lecturas o escrituras de realm síncronas en el hilo de la IU, puedes permitir explícitamente el uso de métodos síncronos con las siguientes opciones SyncConfiguration:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); } });
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v("EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread.") } })
Buscar un objeto específico por clave primaria
Para encontrar un objeto con un valor de clave principal específico, abra un reino y consulte el campo de clave principal para obtener el valor de clave principal deseado utilizando el método RealmQuery.equalTo():
ProjectTask task = realm.where(ProjectTask.class).equalTo("_id", PRIMARY_KEY_VALUE.get()).findFirst(); Log.v("EXAMPLE", "Fetched object by primary key: " + task);
val task = realm.where(ProjectTask::class.java) .equalTo("_id", ObjectId.get()).findFirst() Log.v("EXAMPLE", "Fetched object by primary key: $task")
Consultar todos los objetos de un tipo determinado
El primer paso de cualquier lectura es obtener todos los objetos de un tipo determinado en un dominio. Con esta colección de resultados, se pueden operar en todas las instancias de un tipo o filtrar y ordenar para refinar los resultados.
Para acceder a todas las instancias de ProjectTask y,Project utilice el método where() para especificar una clase:
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); RealmQuery<Project> projectsQuery = realm.where(Project.class);
val tasksQuery = realm.where(ProjectTask::class.java) val projectsQuery = realm.where(Project::class.java)
Filtro de queries basadas en las propiedades del objeto
Un filtro selecciona un subconjunto de resultados según el valor de una o más propiedades de un objeto. Realm ofrece un completo motor de consultas que permite definir filtros. El uso más común es encontrar objetos donde una propiedad determinada coincide con un valor específico. Además, permite comparar cadenas, agregar conjuntos de números y usar operadores lógicos para crear consultas complejas.
En el siguiente ejemplo, utilizamos los operadores de comparación del motor de consulta para:
Encuentre tareas de alta prioridad comparando el valor de la propiedad
prioritycon un número umbral, por encima del cual la prioridad puede considerarse alta.Encuentre tareas recién iniciadas o de corta duración observando si la propiedad
progressMinutesse encuentra dentro de un rango determinado.Encuentre tareas no asignadas buscando tareas donde la propiedad
assigneesea igual a nulo.Encuentre tareas asignadas a compañeros de equipo específicos, Ali o Jamie, viendo si la propiedad
assigneeestá en una lista de nombres.
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); Log.i("EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan("priority", 5).count()); Log.i("EXAMPLE", "Just-started or short tasks: " + tasksQuery.between("progressMinutes", 1, 10).count()); Log.i("EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count()); Log.i("EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.in("assignee", new String[]{"Ali", "Jamie"}).count());
val tasksQuery = realm.where(ProjectTask::class.java) Log.i( "EXAMPLE", "High priority tasks: " + tasksQuery.greaterThan( "priority", 5 ).count() ) Log.i( "EXAMPLE", "Just-started or short tasks: " + tasksQuery.between( "progressMinutes", 1, 10 ).count() ) Log.i( "EXAMPLE", "Unassigned tasks: " + tasksQuery.isNull("assignee").count() ) Log.i( "EXAMPLE", "Ali or Jamie's tasks: " + tasksQuery.`in`( "assignee", arrayOf( "Ali", "Jamie" ) ).count() )
Ordene los resultados del query
Una operación de ordenación permite configurar el orden en que Realm devuelve los objetos consultados. Puede ordenarlos según una o más propiedades de los objetos de la colección de resultados.
Realm solo garantiza un orden consistente de resultados cuando los resultados están ordenados.
El siguiente código ordena los proyectos por nombre en orden alfabético inverso (es decir, orden "descendente").
RealmQuery<Project> projectsQuery = realm.where(Project.class); RealmResults<Project> results = projectsQuery.sort("name", Sort.DESCENDING).findAll();
val projectsQuery = realm.where(Project::class.java) val results = projectsQuery.sort("name", Sort.DESCENDING).findAll()
Consultar una relación
Considere la siguiente relación entre las clases Human y Cat. Esta disposición permite que cada humano tenga un solo gato:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
Para consultar esta relación, utilice la notación de puntos en una consulta para acceder a cualquier propiedad del objeto vinculado:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ); realm.executeTransaction(transactionRealm -> { Human owner = transactionRealm.where(Human.class).equalTo("cat.name", "bucky").findFirst(); Cat cat = owner.getCat(); Log.v("EXAMPLE", "Queried for humans with cats named 'bucky'. Found " + owner.getName() + ", who owns " + cat.getName()); }); realm.close(); } });
Considere la siguiente relación entre las clases Person y Dog. Esta disposición permite que cada persona tenga un solo perro:
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
Para consultar esta relación, utilice la notación de puntos en una consulta para acceder a cualquier propiedad del objeto vinculado:
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val owner = transactionRealm.where<Person>().equalTo("dog.name", "henry").findFirst() val dog = owner?.dog Log.v("EXAMPLE", "Queried for people with dogs named 'henry'. Found $owner, owner of $dog") } realm.close() } })
Consultar una relación inversa
Considere la siguiente relación entre las clases Cat y Human. En este ejemplo, todos los gatos se vinculan a su humano (o a varios humanos, si varios objetos humanos hacen referencia al mismo gato). Realm calcula automáticamente los propietarios de cada gato basándose en el nombre de campo que proporcione a la anotación @LinkingObjects:
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; import io.realm.annotations.PrimaryKey; public class Cat extends RealmObject { private ObjectId _id = new ObjectId(); private String name = null; private final RealmResults<Human> owner = null; public Cat(String name) { this.name = name; } public Cat() { } public ObjectId get_id() { return _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public RealmResults<Human> getOwner() { return owner; } }
import org.bson.types.ObjectId; import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Human extends RealmObject { private ObjectId _id = new ObjectId(); private String name; private Cat cat; public Human(String name) { this.name = name; } public Human() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Cat getCat() { return cat; } public void setCat(Cat cat) { this.cat = cat; } public ObjectId get_id() { return _id; } }
Para consultar esta relación, utilice la notación de puntos en una consulta para acceder a cualquier propiedad del objeto vinculado:
SyncConfiguration config = new SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build(); Realm.getInstanceAsync(config, new Realm.Callback() { public void onSuccess(Realm realm) { Log.v("EXAMPLE", "Successfully opened a realm."); realm.executeTransaction(transactionRealm -> { Cat cat = transactionRealm.where(Cat.class) .equalTo("owner.name", "steven").findFirst(); Human owner = cat.getOwner().first(); Log.v("EXAMPLE", "Queried for cats with owners named 'steven'. Found " + cat.getName() + ", owned by " + owner.getName()); }); realm.close(); } });
Considere la siguiente relación entre las clases Dog y Person. En este ejemplo, todos los perros se vinculan a su dueño (o a varios dueños, si varios objetos persona se refieren al mismo perro). Realm calcula automáticamente los dueños de cada perro basándose en el nombre de campo que proporcione a la anotación @LinkingObjects:
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Dog(var name : String? = null): RealmObject() { var _id : ObjectId = ObjectId() val owner: RealmResults<Person>? = null }
import io.realm.RealmObject import io.realm.annotations.PrimaryKey import org.bson.types.ObjectId open class Person(var name : String? = null) : RealmObject() { var _id : ObjectId = ObjectId() var dog: Dog? = null }
Para consultar esta relación, utilice la notación de puntos en una consulta para acceder a cualquier propiedad del objeto vinculado:
val config = SyncConfiguration.Builder(app.currentUser(), PARTITION) .allowQueriesOnUiThread(true) .allowWritesOnUiThread(true) .build() Realm.getInstanceAsync(config, object : Realm.Callback() { override fun onSuccess(realm: Realm) { Log.v( "EXAMPLE", "Successfully opened a realm with reads and writes allowed on the UI thread." ) realm.executeTransaction { transactionRealm -> val dog = transactionRealm.where<Dog>() .equalTo("owner.name", "dwayne").findFirst() val owner = dog?.owner?.first() Log.v("EXAMPLE", "Queried for dogs with owners named 'dwayne'. Found $dog, owned by $owner") } realm.close() } })
Datos agregados
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */ Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"));
val tasksQuery = realm.where(ProjectTask::class.java) /* Aggregate operators do not support dot-notation, so you cannot directly operate on a property of all of the objects in a collection property. You can operate on a numeric property of the top-level object, however: */Log.i("EXAMPLE", "Tasks average priority: " + tasksQuery.average("priority"))