过滤数据 - Java SDK
在此页面上
查询引擎
要筛选 Realm 中的数据,请使用 Realm 查询引擎。
使用 Java SDK 访问查询引擎的方法有两种:
流式接口
Java SDK使用 Fluent 接口 构造传递给查询引擎的多子句查询。
请参阅 RealmQuery API 获取可用方法的完整列表。
可使用多种类型的操作符来过滤 Realm 集合。过滤器的工作方式是对所过滤的集合中的每个对象计算操作符表达式。如果表达式解析为 true
,Realm 数据库会将该对象包含在结果集合中。
表达式由以下任一内容组成:
当前正在评估的对象的某个属性的名称。
一个运算符和最多两个参数表达式。
文字字符串、数字或日期。
关于本节中的示例
本节中的示例使用了一个任务列表应用的简单数据集。两种 Realm 对象类型分别是 Project
和 Task
。Task
具有名称、受让人名称和已完成标志。其中还有一个任意的优先级数字(数值越高表示越重要)以及处理所花费的分钟数。Project
具有零个或多个 Tasks
。
请参阅 Project
和 Task
这两个类的模式,如下所示:
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()
比较操作符。
搜索中最直接的操作就是比较值。
Operator | 说明 |
---|---|
between | 如果左侧数值或日期表达式的结果在右侧范围内或落在该范围上,则计算结果为 true 。对于日期,如果左侧日期在右侧日期范围内,则计算结果为 true 。 |
equalTo | 如果左侧表达式等于右侧表达式,则计算结果为 true 。 |
greaterThan | 如果左侧的数值或日期表达式大于右侧的数值或日期表达式,则计算结果为 true 。对于日期,如果左侧日期晚于右侧日期,则计算结果为 true 。 |
greaterThanOrEqualTo | 如果左侧数值或日期表达式大于或等于右侧数值或日期表达式,则计算结果为 true 。对于日期,如果左侧日期晚于或等于右侧日期,则计算结果为 true 。 |
in | 如果左侧表达式在右侧列表中,则计算结果为 true 。 |
lessThan | 如果左侧数值或日期表达式小于右侧数值或日期表达式,则计算结果为 true 。对于日期,如果左侧日期早于右侧日期,则计算结果为 true 。 |
lessThanOrEqualTo | 如果左侧数值表达式小于或等于右侧数值表达式,则计算结果为 true 。对于日期,如果左侧日期早于或等于右侧日期,则计算结果为 true 。 |
notEqualTo | 如果左侧表达式不等于右侧表达式,则计算结果为 true 。 |
例子
以下示例使用查询引擎的比较运算符执行以下操作:
通过将
priority
属性值与阈值数字进行比较来查找高优先级任务,而高于该阈值的优先级可视为高优先级。通过查看
progressMinutes
属性是否在特定范围内来查找刚刚启动或短时间运行的任务。通过查找
assignee
属性等于null
的任务来查找未分配的任务。通过查看
assignee
属性是否在名称列表中来查找分配给团队成员 Ali 或 Jamie 的任务。
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())
逻辑操作符
您可以使用逻辑运算符创建复合谓词。
Operator | 说明 |
---|---|
and | 如果左侧和右侧表达式的值均为 true ,则计算结果为 true : |
not | 对给定表达式的结果予以否定。 |
or | 如果任一表达式返回 true ,则计算结果为 true 。 |
例子
我们可以使用查询语言的逻辑运算符来查找 Ali 已完成的所有任务。也就是说,我们会查找 assignee
属性值等于“Ali”且 isComplete
属性值为 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.")
字符串操作符
您可以使用这些字符串运算符来比较字符串值。类似正则表达式的通配符可提升搜索灵活性。
Operator | 说明 |
---|---|
beginsWith | 如果左侧字符串表达式以右侧字符串表达式开头,则计算结果为 true 。这与 contains 类似,但仅当在右侧字符串表达式的最末尾找到左侧字符串表达式时才匹配。 |
contains | 如果在左侧字符串表达式中的任意位置找到右侧字符串表达式,则计算结果为 true 。 |
endsWith | 如果左侧字符串表达式以右侧字符串表达式结尾,则计算结果为 true 。这与 contains 类似,但仅当在右侧字符串表达式的最末尾找到左侧字符串表达式时才匹配。 |
like | 如果左侧字符串表达式与右侧字符串通配符字符串表达式匹配,则计算结果为
例如,通配符字符串“d?g”匹配“dog”、“dig”和“dug”,但不匹配“ding”、“dg”或“a dog”。 |
equalTo | 如果左侧字符串在字典顺序上等于右侧字符串,则计算结果为 true 。 |
例子
我们使用查询引擎的字符串运算符来查找名称以字母“e”开头的项目,以及名称包含“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())
注意
不区分大小写的字符限制
不区分大小写的字符串操作符仅支持 Latin Basic
、Latin Supplement
、Latin Extended A
和 Latin Extended B (UTF-8 range 0–591)
字符集。当使用 equalTo
、notEqualTo
、contains
、endsWith
,beginsWith
或 like
时,在查询中设置不区分大小写标志仅对英文字符有效。
聚合操作符
您可将聚合运算符应用于 Realm 对象的集合属性。聚合运算符会遍历集合并将其简化为单个值。
Operator | 说明 |
---|---|
average | 计算集合中给定数值属性的平均值。 |
count | 计算给定集合中的对象数量。 |
max | 计算集合中给定数值属性的最大值。 |
min | 计算集合中给定数值属性的最小值。 |
sum | 计算集合中给定数值属性的总和。 |
例子
我们将创建几个筛选器来显式该数据的不同分面:
平均任务优先级大于 5 的项目。
长时间运行的项目。
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"))
筛选、排序、限制、唯一和链式查询
关于本节中的示例
本节中的示例使用两种 Realm 对象类型: Teacher
和 Student
。
请参阅下面这两个类的模式:
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 }
筛选器
您可以使用 Fluent 接口 的操作符方法构建筛选器 由 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()
这将为您提供 RealmResults 类的一个新实例,其中包含名为“Ms.Langtree”或“Mrs. Jacobs”的教师。
RealmQuery
包括几个可以执行查询的方法:
findAll() 块,直到找到所有符合查询条件的对象
findAllAsync() 会立即返回并在后台线程上异步查找符合查询条件的所有对象
findFirst()块,直到找到第一个满足查询条件的对象
findFirstAsync() 会立即返回并在后台线程上异步查找符合查询条件的第一个对象
查询使用 RealmResults 类型返回匹配 Realm 对象的引用列表。
链接查询
在引用对象属性时,可以使用点表示法来引用该对象的子属性。您可以使用点表示法来引用嵌入式对象的属性和关系。
例如,考虑查询有学生名为“Wirt”或“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()
您甚至可以使用点表示法来查询反向关系:
// 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()
对结果进行排序
重要
Realm 按照您指定的顺序应用 distinct()
、sort()
和 limit()
方法。根据数据集的不同,这可能会改变查询结果。通常来说,您应最后应用 limit()
,避免意外的结果集。
您可以使用 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")
默认以升序排列整理结果。 要按降序排列结果,请将 Sort.DESCENDING
作为第二个参数传递。 您可以通过传递属性数组而不是单个属性来解决相同属性值之间的排序顺序联系:如果出现联系,Realm 将按后续属性对联系对象进行排序。
注意
字符串排序限制
Realm 对大小写字母使用非标准排序,同时对它们进行排序,而不是先对大写字母进行排序。因此,'- !"#0&()*,./:;?_+<=>123aAbBcC...xXyYzZ
是 Realm 中的实际排序顺序。此外,排序字符串仅支持 Latin Basic
、Latin Supplement
、Latin Extended A
和 Latin Extended B (UTF-8 range 0–591)
字符集。
限制结果
您可以使用 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()
有限的结果集合会像任何其他查询结果一样自动更新。 因此,随着基础数据的更改,对象可能会从集合中删除。
提示
Realm 优化不需要分页
一些数据库鼓励对结果进行分页,以避免从磁盘读取不必要的数据或使用过多的内存。
由于 Realm 查询出现延迟,所以没有必要采取这样的措施。 Realm 仅在显式访问查询结果时加载对象。
唯一结果
您可以使用 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()
您只能对整数、长整型、短整型和String
字段调用distinct()
;其他字段类型将抛出异常。与排序一样,您可以指定多个字段来解析关系。
链接查询
通过调用 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()
where()
方法返回一个RealmQuery
,您可以使用find
方法将其解析为RealmResults
。 筛选后的结果只能返回与原始结果集类型相同的对象,但可以使用任何筛选器。
使用 Realm 查询语言进行查询
10.4.0 版本中的新增功能。
您还可以使用 Realm 查询语言来查询域,这是一种基于字符串的查询语言,用于在从域中检索对象时限制搜索。
您可以使用RealmQuery.rawPredicate() 。 有关语法、用法和限制的更多信息,请参阅RQL 参考。
Realm Query Language 可以使用 Realm 模型类中定义的类和属性名称,也可以使用由@RealmField
定义的内部名称。您可以将原始谓词与其他原始谓词或使用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()