Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ /

过滤数据 - Java SDK

在此页面上

  • 查询引擎
  • 流式接口
  • 关于本节中的示例
  • 比较操作符。
  • 逻辑操作符
  • 字符串操作符
  • 聚合操作符
  • 筛选、排序、限制、唯一和链式查询
  • 关于本节中的示例
  • 筛选器
  • 对结果进行排序
  • 限制结果
  • 唯一结果
  • 链接查询
  • 使用 Realm 查询语言进行查询

要筛选 Realm 中的数据,请使用 Realm 查询引擎。

使用 Java SDK 访问查询引擎的方法有两种:

  • 流式接口

  • Realm 查询语言

Java SDK使用 Fluent 接口 构造传递给查询引擎的多子句查询。

请参阅 RealmQuery API 获取可用方法的完整列表。

可使用多种类型的操作符来过滤 Realm 集合。过滤器的工作方式是对所过滤的集合中的每个对象计算操作符表达式。如果表达式解析为 true,Realm 数据库会将该对象包含在结果集合中。

表达式由以下任一内容组成:

  • 当前正在评估的对象的某个属性的名称。

  • 一个运算符和最多两个参数表达式。

  • 文字字符串、数字或日期。

本节中的示例使用了一个任务列表应用的简单数据集。两种 Realm 对象类型分别是 ProjectTaskTask 具有名称、受让人名称和已完成标志。其中还有一个任意的优先级数字(数值越高表示越重要)以及处理所花费的分钟数。Project 具有零个或多个 Tasks

请参阅 ProjectTask 这两个类的模式,如下所示:

ProjectTask.java
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 {
@PrimaryKey
public ObjectId _id;
@Required
public String name;
public String assignee;
public int progressMinutes;
public boolean isComplete;
public int priority;
@Required
public String _partition;
}
Project.java
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 {
@PrimaryKey
public ObjectId _id;
@Required
public String name;
public RealmList<ProjectTask> tasks = new RealmList<>();
}
ProjectTask.kt
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
import io.realm.annotations.Required
import org.bson.types.ObjectId
open class ProjectTask(
@PrimaryKey
var _id: ObjectId = ObjectId(),
@Required
var name: String = "",
var assignee: String? = null,
var progressMinutes: Int = 0,
var isComplete: Boolean = false,
var priority: Int = 0,
var _partition: String = ""
): RealmObject()
Project.kt
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(
@PrimaryKey
var _id: ObjectId = ObjectId(),
@Required
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

如果左侧字符串表达式与右侧字符串通配符字符串表达式匹配,则计算结果为 true。通配符字符串表达式是使用普通字符和两个特殊通配符的字符串:

  • * 通配符可与零个或多个任意字符匹配

  • ? 通配符与任意字符匹配。

例如,通配符字符串“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 BasicLatin SupplementLatin Extended ALatin Extended B (UTF-8 range 0–591) 字符集。当使用 equalTonotEqualTocontainsendsWithbeginsWithlike 时,在查询中设置不区分大小写标志仅对英文字符有效。

您可将聚合运算符应用于 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 对象类型: TeacherStudent

请参阅下面这两个类的模式:

Teacher.java
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; }
}
Student.java
import io.realm.RealmObject;
import io.realm.RealmResults;
import io.realm.annotations.LinkingObjects;
public class Student extends RealmObject {
private String name;
private Integer year;
@LinkingObjects("students")
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; }
}
Teacher.kt
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
}
Student.kt
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
@LinkingObjects("students")
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 BasicLatin SupplementLatin Extended ALatin 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 。 筛选后的结果只能返回与原始结果集类型相同的对象,但可以使用任何筛选器。

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()

提示

另请参阅:Realm 查询语言示例

您还可以在以下页面找到有用的 Realm 查询语言示例:

后退

删除