Motor de consultas
Para filtrar datos en tu entorno, utiliza el motor de query de Realm.
Hay dos formas de acceder al motor de consultas con el SDK de Java:
Interfaz fluida
El SDK de Java utiliza una interfaz Fluent para construir consultas de múltiples cláusulas que se pasan al motor de consultas.
Consulte la API de RealmQuery para obtener una lista completa de los métodos disponibles.
Hay varios tipos de operadores disponibles para filtrar una colección de Realm. Los filtros funcionan evaluando una expresión de operador para cada objeto de la colección que se filtra. Si la expresión se resuelve como trueLa base de datos Realm incluye el objeto en la colección de resultados.
Una expresión consta de uno de los siguientes:
El nombre de una propiedad del objeto que se está evaluando actualmente.
Un operador y hasta dos expresiones de argumentos.
Una cadena literal, un número o una fecha.
Acerca de los ejemplos en esta sección
Los ejemplos de esta sección utilizan un conjunto de datos simple para una aplicación de lista de tareas. Los dos tipos de objeto Realm son Project y Task. Un Task tiene un nombre, el nombre del asignado y un indicador de finalización. También hay un número arbitrario para la prioridad (cuanto mayor sea la prioridad, más importante) y un recuento de minutos dedicados a trabajar en ella. 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()
Operadores de comparación
La operación más sencilla en una búsqueda es comparar valores.
Operador | Descripción |
|---|---|
| Se evalúa como |
equalTo | Se evalúa como |
greaterThan | Se evalúa como |
greaterThanOrEqualTo | Se evalúa como |
| Se evalúa como |
lessThan | Se evalúa como |
lessThanOrEqualTo | Se evalúa como |
notEqualTo | Se evalúa como |
Ejemplo
El siguiente ejemplo utiliza 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 anull.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())
Operadores lógicos
Puedes crear predicados compuestos utilizando operadores lógicos.
Operador | Descripción |
|---|---|
and | Se evalúa como |
not | Niega el resultado de la expresión dada. |
or | Se evalúa como |
Ejemplo
Podemos usar los operadores lógicos del lenguaje de consulta para encontrar todas las tareas completadas de Ali. Es decir, buscamos todas las tareas donde el valor de la propiedad assignee es igual a 'Ali' y el valor de la propiedad isComplete es true:
RealmQuery<ProjectTask> tasksQuery = realm.where(ProjectTask.class); Log.i("EXAMPLE", "Ali has completed " + tasksQuery.equalTo("assignee", "Ali").and().equalTo("isComplete", true).findAll().size() + " tasks.");
val tasksQuery = realm.where(ProjectTask::class.java) Log.i("EXAMPLE", "Ali has completed " + tasksQuery.equalTo("assignee", "Ali").and() .equalTo("isComplete", true).findAll().size + " tasks.")
Operadores de String
Puedes comparar valores de cadena usando estos operadores. Los comodines tipo expresiones regulares ofrecen mayor flexibilidad en la búsqueda.
Operador | Descripción |
|---|---|
beginsWith | Se evalúa como |
| Evalúa como |
endsWith | Se evalúa como |
like | Se evalúa como
Por ejemplo, la cadena comodín "d?g" coincide con "perro", "dig" y "dug", pero no con "ding", "dg" o "un perro". |
equalTo | Se evalúa como |
Ejemplo
Utilizamos los operadores de cadena del motor de consulta para encontrar proyectos con un nombre que comience con la letra 'e' y proyectos con nombres que contengan 'ie':
RealmQuery<Project> projectsQuery = realm.where(Project.class); // Pass Case.INSENSITIVE as the third argument for case insensitivity. Log.i("EXAMPLE", "Projects that start with 'e': " + projectsQuery.beginsWith("name", "e", Case.INSENSITIVE).count()); Log.i("EXAMPLE", "Projects that contain 'ie': " + projectsQuery.contains("name", "ie").count());
val projectsQuery = realm.where(Project::class.java) // Pass Case.INSENSITIVE as the third argument for case insensitivity. Log.i("EXAMPLE", "Projects that start with 'e': " + projectsQuery.beginsWith("name", "e", Case.INSENSITIVE).count()) Log.i("EXAMPLE", "Projects that contain 'ie': " + projectsQuery.contains("name", "ie").count())
Nota
Limitaciones de caracteres que no distinguen entre mayúsculas y minúsculas
Los operadores de cadena que no distinguen entre mayúsculas y minúsculas solo admiten los conjuntos de caracteres Latin Basic, Latin Supplement, Latin Extended A y Latin Extended B (UTF-8 range 0–591). Activar la opción de no distinguir entre mayúsculas y minúsculas en las consultas al usar equalTo, notEqualTo, contains, endsWith, beginsWith o like solo funciona con caracteres de la configuración regional en inglés.
Operadores agregados
Se puede aplicar un operador de agregación a una propiedad de colección de un objeto Realm. Los operadores de agregación recorren una colección y la reducen a un único valor.
Operador | Descripción |
|---|---|
average | Se evalúa como el valor promedio de una propiedad numérica dada en una colección. |
count | Se evalúa como el número de objetos en la colección dada. |
max | Se evalúa como el valor más alto de una propiedad numérica dada en una colección. |
min | Se evalúa como el valor más bajo de una propiedad numérica dada en una colección. |
sum | Se evalúa como la suma de una propiedad numérica dada en una colección. |
Ejemplo
Creamos un par de filtros para mostrar diferentes facetas de los datos:
Proyectos con prioridad de tareas promedio superior a 5.
Proyectos de larga duración.
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"))
Consultas de filtro, ordenamiento, límite, únicas y en cadena
Acerca de los ejemplos de esta sección
Los ejemplos de esta sección utilizan dos tipos de objetos Realm: Teacher y Student.
Vea el esquema de estas dos clases a continuación:
import io.realm.RealmList; import io.realm.RealmObject; public class Teacher extends RealmObject { private String name; private Integer numYearsTeaching; private String subject; private RealmList<Student> students; public Teacher() {} public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getNumYearsTeaching() { return numYearsTeaching; } public void setNumYearsTeaching(Integer numYearsTeaching) { this.numYearsTeaching = numYearsTeaching; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public RealmList<Student> getStudents() { return students; } public void setStudents(RealmList<Student> students) { this.students = students; } }
import io.realm.RealmObject; import io.realm.RealmResults; import io.realm.annotations.LinkingObjects; public class Student extends RealmObject { private String name; private Integer year; private final RealmResults<Teacher> teacher = null; public Student() {} public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getYear() { return year; } public void setYear(Integer year) { this.year = year; } public RealmResults<Teacher> getTeacher() { return teacher; } }
import io.realm.RealmList import io.realm.RealmObject open class Teacher : RealmObject() { var name: String? = null var numYearsTeaching: Int? = null var subject: String? = null var students: RealmList<Student>? = null }
import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.LinkingObjects open class Student : RealmObject() { var name: String? = null var year: Int? = null val teacher: RealmResults<Teacher>? = null }
Filtros
Puede crear filtros utilizando los métodos de operador de la interfaz fluida expuesta por la clase RealmQuery:
// Build the query looking at all teachers: RealmQuery<Teacher> query = realm.where(Teacher.class); // Add query conditions: query.equalTo("name", "Ms. Langtree"); query.or().equalTo("name", "Mrs. Jacobs"); // Execute the query: RealmResults<Teacher> result1 = query.findAll(); // Or alternatively do the same all at once (the "Fluent interface"): RealmResults<Teacher> result2 = realm.where(Teacher.class) .equalTo("name", "Ms. Langtree") .or() .equalTo("name", "Mrs. Jacobs") .findAll();
// Build the query looking at all teachers: val query = realm.where(Teacher::class.java) // Add query conditions: query.equalTo("name", "Ms. Langtree") query.or().equalTo("name", "Mrs. Jacobs") // Execute the query: val result1 = query.findAll() // Or alternatively do the same all at once (the "Fluent interface"): val result2 = realm.where(Teacher::class.java) .equalTo("name", "Ms. Langtree") .or() .equalTo("name", "Mrs. Jacobs") .findAll()
Esto le proporciona una nueva instancia de la clase RealmResults, que contiene profesores con el nombre "Sra. Langtree" o "Sra. Jacobs".
RealmQuery Incluye varios métodos que pueden ejecutar consultas:
findAll() se bloquea hasta que encuentra todos los objetos que cumplen las condiciones de consulta
findAllAsync() regresa inmediatamente y encuentra todos los objetos que cumplen las condiciones de consulta de forma asincrónica en un hilo en segundo plano.
findFirst() se bloquea hasta que encuentra el primer objeto que cumple las condiciones de consulta
findFirstAsync() regresa inmediatamente y encuentra el primer objeto que cumple las condiciones de consulta de forma asincrónica en un hilo en segundo plano.
Las consultas devuelven una lista de referencias a los objetos Realm coincidentes utilizando el tipo RealmResults.
Consultas de enlaces
Al referirse a una propiedad de un objeto, se puede usar la notación de puntos para referirse a sus propiedades secundarias. También se pueden usar para referirse a las propiedades de objetos incrustados y relaciones.
Por ejemplo, considere una consulta para todos los profesores con un estudiante llamado "Wirt" o "Greg":
// Find all teachers who have students with the names "Wirt" or "Greg" RealmResults<Teacher> result = realm.where(Teacher.class) .equalTo("students.name", "Wirt") .or() .equalTo("students.name", "Greg") .findAll();
// Find all teachers who have students with the names "Wirt" or "Greg" val result = realm.where(Teacher::class.java) .equalTo("students.name", "Wirt") .or() .equalTo("students.name", "Greg") .findAll()
Incluso puedes utilizar la notación de puntos para consultar relaciones inversas:
// Find all students who have teachers with the names "Ms. Langtree" or "Mrs. Jacobs" RealmResults<Student> result = realm.where(Student.class) .equalTo("teacher.name", "Ms. Langtree") .or() .equalTo("teacher.name", "Mrs. Jacobs") .findAll();
// Find all students who have teachers with the names "Ms. Langtree" or "Mrs. Jacobs" val result = realm.where(Student::class.java) .equalTo("teacher.name", "Ms. Langtree") .or() .equalTo("teacher.name", "Mrs. Jacobs") .findAll()
Ordenar resultados
Importante
Realm aplica los métodos distinct(), sort() y limit() en el orden especificado. Según el conjunto de datos, esto puede alterar el resultado de la consulta. Generalmente, se recomienda aplicar limit() al final para evitar conjuntos de resultados no deseados.
Puede definir el orden de los resultados de la consulta utilizando el método sort():
// Find all students in year 7, and sort them by name RealmResults<Student> result = realm.where(Student.class) .equalTo("year", 7) .sort("name") .findAll(); // Alternatively, find all students in year 7 RealmResults<Student> unsortedResult = realm.where(Student.class) .equalTo("year", 7) .findAll(); // then sort the results set by name RealmResults<Student> sortedResult = unsortedResult.sort("name");
// Find all students in year 7, and sort them by name val result: RealmResults<Student> = realm.where(Student::class.java) .equalTo("year", 7L) .sort("name") .findAll() // Alternatively, find all students in year 7 val unsortedResult: RealmResults<Student> = realm.where(Student::class.java) .equalTo("year", 7L) .findAll() // then sort the results set by name val sortedResult = unsortedResult.sort("name")
Los ordenamientos organizan los resultados en orden ascendente de forma predeterminada. Para organizar los resultados en orden descendente, pase Sort.DESCENDING como segundo argumento. Puede resolver los empates de ordenamiento entre valores de propiedad idénticos pasando una matriz de propiedades en lugar de una sola: en caso de empate, Realm ordena los objetos empatados por las propiedades subsiguientes.
Nota
Limitaciones de la ordenación de cadenas
Realm utiliza un ordenamiento no estándar para mayúsculas y minúsculas, ordenándolas juntas en lugar de ordenar primero las mayúsculas. Por lo tanto, '- !"#0&()*,./:;?_+<=>123aAbBcC...xXyYzZ es el orden de clasificación real en Realm. Además, la ordenación de cadenas solo admite los conjuntos de caracteres Latin Basic, Latin Supplement, Latin Extended A y Latin Extended B (UTF-8 range 0–591).
Limitar los resultados
Puede limitar el número de resultados de la consulta a un número máximo específico utilizando el método limit():
// Find all students in year 8, and limit the results collection to 10 items RealmResults<Student> result = realm.where(Student.class) .equalTo("year", 8) .limit(10) .findAll();
// Find all students in year 8, and limit the results collection to 10 items val result: RealmResults<Student> = realm.where(Student::class.java) .equalTo("year", 8L) .limit(10) .findAll()
Las colecciones de resultados limitadas se actualizan automáticamente como cualquier otro resultado de consulta. Por lo tanto, los objetos podrían desaparecer de la colección a medida que cambian los datos subyacentes.
Tip
La paginación no es necesaria para la optimización del dominio
Algunas bases de datos incentivan la paginación de los resultados con límites para evitar leer datos innecesarios del disco o usar demasiada memoria.
Dado que las consultas de Realm son perezosas, no es necesario tomar estas medidas. Realm solo carga objetos de los resultados de la consulta cuando se accede a ellos explícitamente.
Tip
Notificaciones eliminadas en resultados limitados
Las notificaciones de colección informan que los objetos se eliminan cuando desaparecen del conjunto de resultados. Esto no significa necesariamente que se hayan eliminado del dominio subyacente, sino que ya no forman parte del resultado de la consulta.
Resultados únicos
Puede reducir los resultados de la consulta a valores únicos para un campo o campos determinados utilizando el método distinct():
// Find all students in year 9, and cap the result collection at 10 items RealmResults<Student> result = realm.where(Student.class) .equalTo("year", 9) .distinct("name") .findAll();
// Find all students in year 9, and cap the result collection at 10 items val result: RealmResults<Student> = realm.where<Student>(Student::class.java) .equalTo("year", 9L) .distinct("name") .findAll()
Solo se puede llamar a distinct() en campos enteros, largos, cortos y String; otros tipos de campo generarán una excepción. Al igual que con la ordenación, se pueden especificar varios campos para resolver empates.
Consultas en cadena
Puede aplicar filtros adicionales a una colección de resultados llamando al método where():
// Find all students in year 9 and resolve the query into a results collection RealmResults<Student> result = realm.where(Student.class) .equalTo("year", 9) .findAll(); // filter the students results again by teacher name RealmResults<Student> filteredResults = result.where().equalTo("teacher.name", "Ms. Langtree").findAll();
// Find all students in year 9 and resolve the query into a results collection val result: RealmResults<Student> = realm.where(Student::class.java) .equalTo("year", 9L) .findAll() // filter the students results again by teacher name val filteredResults = result.where().equalTo("teacher.name", "Ms. Langtree").findAll()
El where() método devuelve un RealmQuery que se puede convertir en un RealmResults mediante un find método. Los resultados filtrados solo pueden devolver objetos del mismo tipo que el conjunto de resultados original, pero pueden usar cualquier otro filtro.
Consulta con el lenguaje de consulta Realm
Nuevo en la versión 10.4.0.
También puedes consultar reinos usando Realm Query Language, un lenguaje de consulta basado en cadenas para restringir las búsquedas al recuperar objetos de un reino.
Puedes utilizar RealmQuery.rawPredicate(). Para más información sobre sintaxis, uso y limitaciones, consulta la referencia del Lenguaje de Consulta de Realm.
El lenguaje de consulta de Realm puede usar los nombres de clase y propiedad definidos en las clases del modelo de Realm o los nombres internos definidos con @RealmField. Puede combinar predicados sin formato con otros predicados sin formato o predicados con seguridad de tipos creados con RealmQuery:
// Build a RealmQuery based on the Student type RealmQuery<Student> query = realm.where(Student.class); // Simple query RealmResults<Student> studentsNamedJane = query.rawPredicate("name = 'Jane'").findAll(); // Multiple predicates RealmResults<Student> studentsNamedJaneOrJohn = query.rawPredicate("name = 'Jane' OR name = 'John'").findAll(); // Collection queries RealmResults<Student> studentsWithTeachers = query.rawPredicate("teacher.@count > 0").findAll(); RealmResults<Student> studentsWithSeniorTeachers = query.rawPredicate("ALL teacher.numYearsTeaching > 5").findAll(); // Sub queries RealmResults<Student> studentsWithMathTeachersNamedSteven = query.rawPredicate("SUBQUERY(teacher, $teacher, $teacher.subject = 'Mathematics' AND $teacher.name = 'Mr. Stevens').@count > 0").findAll(); // Sort, Distinct, Limit RealmResults<Student> students = query.rawPredicate("teacher.@count > 0 SORT(year ASCENDING) DISTINCT(name) LIMIT(5)").findAll(); // Combine two raw predicates RealmResults<Student> studentsNamedJaneOrHenry = query.rawPredicate("name = 'Jane'") .rawPredicate("name = 'Henry'").findAll(); // Combine raw predicate with type-safe predicate RealmResults<Student> studentsNamedJaneOrHenryAgain = query.rawPredicate("name = 'Jane'") .equalTo("name", "Henry").findAll();
// Build a RealmQuery based on the Student type val query = realm.where(Student::class.java) // Simple query val studentsNamedJane = query.rawPredicate("name = 'Jane'").findAll() // Multiple predicates val studentsNamedJaneOrJohn = query.rawPredicate("name = 'Jane' OR name = 'John'").findAll() // Collection queries val studentsWithTeachers = query.rawPredicate("teacher.@count > 0").findAll() val studentsWithSeniorTeachers = query.rawPredicate("ALL teacher.numYearsTeaching > 5").findAll() // Sub queries val studentsWithMathTeachersNamedSteven = query.rawPredicate("SUBQUERY(teacher, \$teacher, \$teacher.subject = 'Mathematics' AND \$teacher.name = 'Mr. Stevens').@count > 0") .findAll() // Sort, Distinct, Limit val students = query.rawPredicate("teacher.@count > 0 SORT(year ASCENDING) DISTINCT(name) LIMIT(5)") .findAll() // Combine two raw predicates val studentsNamedJaneOrHenry = query.rawPredicate("name = 'Jane'") .rawPredicate("name = 'Henry'").findAll() // Combine raw predicate with type-safe predicate val studentsNamedJaneOrHenryAgain = query.rawPredicate("name = 'Jane'") .equalTo("name", "Henry").findAll()
Tip
Ejemplos del lenguaje de consulta Realm
También puede encontrar ejemplos útiles del lenguaje de consulta Realm en las siguientes páginas: