Docs 菜单

Docs 主页开发应用程序Atlas Device SDKs

过滤数据 - Swift SDK

在此页面上

  • 概述
  • 关于本页中的示例
  • Realm Swift 查询 API
  • 操作符
  • 比较操作符。
  • 集合
  • 逻辑操作符
  • 字符串操作符
  • 地理空间操作符
  • 聚合操作符
  • 设置操作符
  • 子查询
  • NSPredicate 查询
  • 表达式
  • 点符号
  • 替代项
  • 操作符
  • 比较操作符。
  • 逻辑操作符
  • 字符串操作符
  • 地理空间操作符
  • 聚合操作符
  • 设置操作符
  • 子查询

要过滤 Realm 中的数据,您可以利用 Realm 的查询引擎。

10.19.0 版的新功能::Realm Swift 查询 API

Realm Swift Query API为 Swift 开发者提供了一种查询数据的惯用方式。使用 Swift 风格的语法来查询 Realm,具有自动完成和类型安全的优点。 Realm Swift Query API 不会取代较新 SDK 版本中的 NSPredicate Query API;相反,您可以使用其中任何一个。

适用于10之前的 SDK 版本。 19 。 0 ,或者对于 Objective-C 开发者,Realm 的查询引擎支持NSPredicate Query。

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

Project 具有零个或多个 Tasks

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

您可以使用以下代码为这些示例设置 Realm:

10.19.0 版本新增:对于早于 10.19.0 的 SDK 版本,请使用 NSPredicate 查询 API。

您可以使用.where Realm Swift 查询 API 构建具有 Swift 风格语法的筛选器:

let realmSwiftQuery = projects.where {
($0.tasks.progressMinutes > 1) && ($0.tasks.assignee == "Ali")
}

此查询 API 会构造一个NSPredicate来执行查询。它为开发者提供了一个可直接使用的类型安全的惯用 API,并抽象出了 NSPredicate 构造。

.where API 接受一个计算结果为 true 或 false 的回调。回调会接收所查询类型的实例,您可以利用编译器静态检查您是否正在创建引用有效属性的有效查询。

在此页面的示例中,我们使用 $0 简写来引用传递到回调中的变量。

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

您可以结合使用 Swift 比较操作符与 Realm Swift Query API ( ==!=>>=<<= )。

例子

以下示例使用查询引擎的比较运算符执行以下操作:

  • 通过将 priority 属性值与阈值数字进行比较来查找高优先级任务,而高于该阈值的优先级可视为高优先级。

  • 通过查看 progressMinutes 属性是否等于或高于特定值来查找长时间运行的任务。

  • 通过查找 assignee 属性等于 null 的任务来查找未分配的任务。

let highPriorityTasks = tasks.where {
$0.priority > 5
}
print("High-priority tasks: \(highPriorityTasks.count)")
let longRunningTasks = tasks.where {
$0.progressMinutes >= 120
}
print("Long running tasks: \(longRunningTasks.count)")
let unassignedTasks = tasks.where {
$0.assignee == nil
}
print("Unassigned tasks: \(unassignedTasks.count)")

您可以使用 .contains 操作符来查询集合中的值。您可以按元素搜索单个值,也可以在某个范围内搜索。

Operator
说明
.in(_ collection:)
如果表达式引用的属性包含给定数组中的元素,则计算结果为 true
.contains(_ element:)
相当于 IN 操作符。如果表达式引用的属性包含该值,则计算结果为 true
.contains(_ range:)
相当于 BETWEEN 操作符。如果表达式引用的属性包含在该范围内的值,则计算结果为 true
.containsAny(in: )
相当于 IN 操作符与 ANY 操作符的组合。如果给定数组中包含的任何元素都存在于集合中,则计算结果为 true

例子

  • 查找 labelsMutableSet 集合属性包含“quick win”的任务。

  • 查找 progressMinutes 属性在给定分钟范围内的任务。

let quickWinTasks = tasks.where {
$0.labels.contains("quick win")
}
print("Tasks labeled 'quick win': \(quickWinTasks.count)")
let progressBetween30and60 = tasks.where {
$0.progressMinutes.contains(30...60)
}
print("Tasks with progress between 30 and 60 minutes: \(progressBetween30and60.count)")

查找 labels MutableSet 集合属性包含给定数组中的任何元素(“quick win”或“bug”)的任务。

let quickWinOrBugTasks = tasks.where {
$0.labels.containsAny(in: ["quick win", "bug"])
}
print("Tasks labeled 'quick win' or 'bug': \(quickWinOrBugTasks.count)")

10.23.0 版本新增IN 操作符

Realm Swift Query API 现在支持 IN 操作符。如果表达式引用的属性包含该值,则计算结果为 true

例子

通过查看 assignee 属性是否在名称列表中来查找分配给团队成员 Ali 或 Jamie 的任务。

let taskAssigneeInAliOrJamie = tasks.where {
let assigneeNames = ["Ali", "Jamie"]
return $0.assignee.in(assigneeNames)
}
print("Tasks IN Ali or Jamie: \(taskAssigneeInAliOrJamie.count)")

您可以使用 Swift 逻辑操作符( &&!|| )来进行复合查询。

例子

我们可以使用查询语言的逻辑运算符来查找 Ali 已完成的所有任务。也就是说,我们会查找 assignee 属性值等于“Ali”且 isComplete 属性值为 true 的所有任务:

let aliComplete = tasks.where {
($0.assignee == "Ali") && ($0.isComplete == true)
}
print("Ali's complete tasks: \(aliComplete.count)")

您可以使用这些字符串运算符来比较字符串值。类似正则表达式的通配符可提升搜索灵活性。

注意

您可以将以下选项与字符串操作符一起使用:

  • .caseInsensitive 不区分大小写。

    $0.name.contains("f", options: .caseInsensitive)
  • .diacriticInsensitive 表示对变音符号不敏感:Realm 会将特殊字符视为基本字符(例如é -> e )。

    $0.name.contains("e", options: .diacriticInsensitive)
Operator
说明
.starts(with value: String)
如果集合包含一个元素且该元素的值以指定字符串值开头,则计算结果为 true
.contains(_ value: String)
如果在左侧字符串表达式中的任意位置找到右侧字符串表达式,则计算结果为 true
.ends(with value: String)
如果集合包含一个元素且该元素的值以指定字符串值结尾,则计算结果为 true
.like(_ value: String)

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

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

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

例如,通配符字符串“d?g”匹配“dog”、“dig”和“dug”,但不匹配“ding”、“dg”或“a dog”。

==
如果左侧字符串在字典顺序上等于右侧字符串,则计算结果为 true
!=
如果左侧字符串在字典顺序上不等于右侧字符串,则计算结果为 true

例子

以下示例使用查询引擎的字符串操作符来查找:

  • 名称以字母“e”开头的项目

  • 名称中包含“ie”的项目

  • 具有与 Al?x 值相似的 assignee 属性的项目

  • 包含类似于 e 的字符且不区分变音符号的项目

// Use the .caseInsensitive option for case-insensitivity.
let startWithE = projects.where {
$0.name.starts(with: "e", options: .caseInsensitive)
}
print("Projects that start with 'e': \(startWithE.count)")
let containIe = projects.where {
$0.name.contains("ie")
}
print("Projects that contain 'ie': \(containIe.count)")
let likeWildcard = tasks.where {
$0.assignee.like("Al?x")
}
print("Tasks with assignees like Al?x: \(likeWildcard.count)")
// Use the .diacreticInsensitive option for diacritic insensitivty: contains 'e', 'E', 'é', etc.
let containElike = projects.where {
$0.name.contains("e", options: .diacriticInsensitive)
}
print("Projects that contain 'e', 'E', 'é', etc.: \(containElike.count)")

注意

字符串排序和不区分大小写的查询仅支持“基本拉丁语”、“拉丁语补充”、“拉丁扩展 A” 和 “拉丁扩展 B”(UTF-8 范围 0-591)中的字符集。

10.47.0 版本的新增功能

使用 geoWithin 操作符查询具有 SDK 提供的形状之一的地理空间数据:

  • GeoCircle

  • GeoBox

  • GeoPolygon

如果满足以下条件,该操作符的计算结果为 true

  • 对象具有包含值为 Point 的 String 属性的地理空间数据“形状”,以及包含经度/纬度对的 List

  • 持久保存的对象的经度/纬度位于地理空间查询形状内。

let companiesInSmallCircle = realm.objects(Geospatial_Company.self).where {
$0.location.geoWithin(smallCircle!)
}
print("Number of companies in small circle: \(companiesInSmallCircle.count)")

有关查询地理空间数据的更多信息,请参阅查询地理空间数据

您可将聚合运算符应用于 Realm 对象的集合属性。聚合运算符会遍历集合并将其简化为单个值。

Operator
说明
.avg
计算集合中给定数值属性的平均值。
.count
计算给定集合中的对象数量。目前仅支持对多关系集合,而不支持基元列表。为了在基元列表上使用 .count,请考虑将基元包装在 Realm 对象中。
.max
计算集合中给定数值属性的最大值。
.min
计算集合中给定数值属性的最小值。
.sum
计算集合中给定数值属性的总和。

例子

我们将创建几个筛选器来显式该数据的不同分面:

  • 平均任务优先级大于 5 的项目。

  • 仅包含优先级低于 5 的低优先级任务的项目。

  • 所有任务的优先级均高于 5 的项目。

  • 包含 5 个以上任务的项目。

  • 长时间运行的项目。

let averageTaskPriorityAbove5 = projects.where {
$0.tasks.priority.avg > 5
}
print("Projects with average task priority above 5: \(averageTaskPriorityAbove5.count)")
let allTasksLowerPriority = projects.where {
$0.tasks.priority.max < 5
}
print("Projects where all tasks are lower priority: \(allTasksLowerPriority.count)")
let allTasksHighPriority = projects.where {
$0.tasks.priority.min > 5
}
print("Projects where all tasks are high priority: \(allTasksHighPriority.count)")
let moreThan5Tasks = projects.where {
$0.tasks.count > 5
}
print("Projects with more than 5 tasks: \(moreThan5Tasks.count)")
let longRunningProjects = projects.where {
$0.tasks.progressMinutes.sum > 100
}
print("Long running projects: \(longRunningProjects.count)")

set 操作符使用特定规则来确定是否将每个输入集合对象传递给输出集合,方法是将给定查询表达式应用于对象的给定列表属性的每个元素。

例子

projects 集合中运行以下查询将返回:

  • 字符串 labels 集中包含“quick win”、“bug”中任意一个的项目。

  • 整数 ratings 集中的任意元素大于 3 的项目。

let projectsWithGivenLabels = projects.where {
$0.tasks.labels.containsAny(in: ["quick win", "bug"])
}
print("Projects with quick wins: \(projectsWithGivenLabels.count)")
let projectsWithRatingsOver3 = projects.where {
$0.tasks.ratings > 3
}
print("Projects with any ratings over 3: \(projectsWithRatingsOver3.count)")

您可以使用子查询通过另一个查询来遍历集合属性。要形成子查询,您必须将表达式放在括号内,并紧随其后添加 .count 聚合器。

(<query>).count > n

如果表达式未生成有效的子查询,会在运行时出现异常。

例子

projects 集合运行以下查询会返回包含名为 Alex 的用户尚未完成的任务的项目。

let subquery = projects.where {
($0.tasks.isComplete == false && $0.tasks.assignee == "Alex").count > 0
}
print("Projects with incomplete tasks assigned to Alex: \(subquery.count)")

你可以使用 NSPredicate 构建过滤器:

过滤器由 NSPredicate 中的表达式组成。表达式由以下任一内容组成:

  • 当前正在评估的对象的某个属性的名称(键路径)。

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

  • 一个值,例如字符串 ('hello') 或数字 (5)。

在引用对象属性时,可以使用点符号来引用该对象的子属性。您甚至可以使用点符号来引用嵌入式对象的属性和关系

例如,请考虑针对某个对象的查询,该对象具有一个 workplace 属性,该属性引用了一个 Workplace 对象。Workplace 对象具有嵌入式对象属性 address。您可以使用链式点符号来引用该地址的 zipcode 属性:

workplace.address.zipcode == 10012

您可以在谓词格式字符串中使用以下替代项:

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

搜索中最直接的操作就是比较值。

重要

类型必须匹配

操作符两侧的类型必须相同。例如,将 ObjectId 与字符串进行比较会导致前提条件失败,并显示类似于下方的消息:

"Expected object of type object id for property 'id' on object of type
'User', but received: 11223344556677889900aabb (Invalid value)"

您可以将任何数值类型与任何其他数值类型进行比较。

Operator
说明
between
如果左侧数值或日期表达式的结果在右侧范围内或落在该范围上,则计算结果为 true。对于日期,如果左侧日期在右侧日期范围内,则计算结果为 true
===
如果左侧表达式等于右侧表达式,则计算结果为 true
>
如果左侧的数值或日期表达式大于右侧的数值或日期表达式,则计算结果为 true。对于日期,如果左侧日期晚于右侧日期,则计算结果为 true
>=
如果左侧数值或日期表达式大于或等于右侧数值或日期表达式,则计算结果为 true。对于日期,如果左侧日期晚于或等于右侧日期,则计算结果为 true
in
如果左侧表达式位于右侧列表或字符串中,则计算结果为 true
<
如果左侧数值或日期表达式小于右侧数值或日期表达式,则计算结果为 true。对于日期,如果左侧日期早于右侧日期,则计算结果为 true
<=
如果左侧数值表达式小于或等于右侧数值表达式,则计算结果为 true。对于日期,如果左侧日期早于或等于右侧日期,则计算结果为 true
!=<>
如果左侧表达式不等于右侧表达式,则计算结果为 true

例子

以下示例使用查询引擎的比较运算符执行以下操作:

  • 通过将 priority 属性值与阈值数字进行比较来查找高优先级任务,而高于该阈值的优先级可视为高优先级。

  • 通过查看 progressMinutes 属性是否等于或高于特定值来查找长时间运行的任务。

  • 通过查找 assignee 属性等于 null 的任务来查找未分配的任务。

  • 通过查看 assignee 属性是否在名称列表中来查找分配给团队成员 Ali 或 Jamie 的任务。

您可以使用逻辑运算符创建复合谓词。

Operator
说明
and
&&
如果左侧和右侧表达式的值均为 true,则计算结果为 true
not
!
对给定表达式的结果予以否定。
or
||
如果任一表达式返回 true,则计算结果为 true

例子

我们可以使用查询语言的逻辑运算符来查找 Ali 已完成的所有任务。也就是说,我们会查找 assignee 属性值等于“Ali”且 isComplete 属性值为 true 的所有任务:

您可以使用这些字符串运算符来比较字符串值。类似正则表达式的通配符可提升搜索灵活性。

注意

您可以将以下修饰符与字符串操作符一起使用:

  • [c] 不区分大小写。

  • [d] 表示对变音符号不敏感:Realm 会将特殊字符视为基本字符(例如é -> e )。

Operator
说明
beginsWith
如果左侧字符串表达式以右侧字符串表达式开头,则计算结果为 true。这与 contains 类似,但仅当在左侧字符串表达式的开头找到右侧字符串表达式时才匹配。
containsin
如果在左侧字符串表达式中的任意位置找到右侧字符串表达式,则计算结果为 true
endsWith
如果左侧字符串表达式以右侧字符串表达式结尾,则计算结果为 true。这与 contains 类似,但仅当在右侧字符串表达式的最末尾找到左侧字符串表达式时才匹配。
like

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

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

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

例如,通配符字符串“d?g”匹配“dog”、“dig”和“dug”,但不匹配“ding”、“dg”或“a dog”。

===
如果左侧字符串在字典顺序上等于右侧字符串,则计算结果为 true
!=<>
如果左侧字符串在字典顺序上不等于右侧字符串,则计算结果为 true

例子

我们使用查询引擎的字符串运算符来查找名称以字母“e”开头的项目,以及名称包含“ie”的项目:

注意

字符串排序和不区分大小写的查询仅支持“基本拉丁语”、“拉丁语补充”、“拉丁扩展 A” 和 “拉丁扩展 B”(UTF-8 范围 0-591)中的字符集。

10.47.0 版本的新增功能

您可以使用 IN 操作符以及 SDK 提供的形状之一执行地理空间查询:

  • GeoCircle

  • GeoBox

  • GeoPolygon

如果满足以下条件,该操作符的计算结果为 true

  • 对象具有包含值为 Point 的 String 属性的地理空间数据“形状”,以及包含经度/纬度对的 List

  • 持久保存的对象的经度/纬度位于地理空间查询形状内。

let filterArguments = NSMutableArray()
filterArguments.add(largeBox)
let companiesInLargeBox = realm.objects(Geospatial_Company.self)
.filter(NSPredicate(format: "location IN %@", argumentArray: filterArguments as? [Any]))
print("Number of companies in large box: \(companiesInLargeBox.count)")

有关查询地理空间数据的更多信息,请参阅查询地理空间数据

您可将聚合运算符应用于 Realm 对象的集合属性。聚合运算符会遍历集合并将其简化为单个值。

Operator
说明
@avg
计算集合中给定数值属性的平均值。
@count
计算给定集合中的对象数量。目前仅支持对多关系集合,而不支持基元列表。为了在基元列表上使用 @count,请考虑将基元包装在 Realm 对象中。
@max
计算集合中给定数值属性的最大值。
@min
计算集合中给定数值属性的最小值。
@sum
计算集合中给定数值属性的总和。

例子

我们将创建几个筛选器来显式该数据的不同分面:

  • 平均任务优先级大于 5 的项目。

  • 长时间运行的项目。

set 操作符使用特定规则来确定是否将每个输入集合对象传递给输出集合,方法是将给定谓词应用于对象的给定列表属性的每个元素。

Operator
说明
ALL
如果集合中所有对象的谓词计算结果均为 true,则返回相应对象。
ANYSOME
如果集合中任一对象的谓词计算结果为 true,则返回相应对象。
NONE
如果集合中所有对象的谓词评估结果均为 false,则返回相应对象。

例子

我们使用查询引擎的 set 操作符来查找:

  • 未包含完成任务的项目。

  • 包含任何最高优先级任务的项目。

您可以使用 SUBQUERY() 谓词函数通过另一个查询来遍历集合属性。SUBQUERY() 具有以下签名:

SUBQUERY(<collection>, <variableName>, <predicate>)
  • collection:要遍历的列表属性的名称

  • variableName:要在子查询中使用的当前元素的变量名称

  • predicate:包含子查询谓词的字符串。您可以使用 variableName 指定的变量名称来引用当前遍历的元素。

例子

projects 集合运行以下过滤器会返回包含名为 Alex 的用户尚未完成的任务的项目。

← 线程 — Swift SDK