Arangodb 简明教程
Querying the Data with AQL
在本章中,我们将讨论如何用 AQL 查询数据。我们的前几章已经讨论过 ArangoDB 已经开发了自己的查询语言,并且命名为 AQL。
现在让我们开始与 AQL 交互。如以下图片所示,在 Web 界面中,按下导航栏顶部的“@ {s0} ”选项卡。会出现一个空白查询编辑器。
需要时,可以通过单击右上角的“查询”或“结果”选项卡在结果视图和编辑器之间进行切换,如下面的图像所示 −
在其他功能中,编辑器具有语法高亮显示、撤消/重做功能和查询保存。有关详细参考,可以参阅官方文档。我们将重点介绍 AQL 查询编辑器的一些基本且常用的功能。
AQL Fundamentals
在 AQL 中,查询表示要实现的最终结果,但不是实现最终结果的过程。此功能通常称为语言的声明属性。此外,AQL 可以查询并修改数据,因此可以通过组合这两个过程创建复杂的查询。
请注意,AQL 完全符合 ACID。读取或修改查询要么全部结束,要么根本不结束。即使读取文档数据也将以一致的数据单元完成。
我们将向我们已经创建的 songs 集合中添加两个新的 @ {s1} 。您可以复制以下查询并将其粘贴到 AQL 编辑器中,而不是输入 −
FOR song IN [
{
title: "Air-Minded Executive", lyricist: "Johnny Mercer",
composer: "Bernie Hanighen", Year: 1940, _key: "Air-Minded"
},
{
title: "All Mucked Up", lyricist: "Johnny Mercer", composer:
"Andre Previn", Year: 1974, _key: "All_Mucked"
}
]
INSERT song IN songs
按左下方的“执行”按钮。
它将在 @ {s2} 集合中写入两个新文档。
此查询描述了 FOR 循环如何在 AQL 中工作;它遍历 JSON 编码文档列表,对集合中每个文档执行编码操作。不同的操作可以是创建新结构、过滤、选择文档、修改或向数据库中插入文档(请参阅直接示例)。从本质上讲,AQL 可以有效地执行 CRUD 操作。
要查找我们数据库中的所有歌曲,让我们再次运行以下查询,这相当于 SQL 类型数据库的 @ {s3} (因为编辑器会记住上次查询,按 @ {s4} 清除编辑器)−
FOR song IN songs
RETURN song
结果集将显示迄今为止保存在 @ {s5} 集合中的歌曲列表,如下面的屏幕截图所示。
可以将 @ {s6} 和 @ {s7} 等操作添加到 @ {s8} 正文以缩小和排序结果。
FOR song IN songs
FILTER song.Year > 1940
RETURN song
以上查询将在“结果”选项卡中显示 1940 年后创作的歌曲(见下图)。
此示例中使用了文档键,但任何其他属性也可以用作过滤的等价物。由于保证文档键是唯一的,因此没有超过一个文档将匹配此过滤器。对于其他属性,可能并非如此。要返回一组活动用户(由称为 status 的属性确定),按名称升序排列,我们使用以下语法 −
FOR song IN songs
FILTER song.Year > 1940
SORT song.composer
RETURN song
LIMIT 2
我们特意包含此示例。在这里,我们观察到 AQL 用红色突出显示的查询语法错误消息。此语法突出显示错误并有助于调试您的查询,如下面的屏幕截图所示。
现在让我们运行正确的查询(注意更正)−
FOR song IN songs
FILTER song.Year > 1940
SORT song.composer
LIMIT 2
RETURN song
Complex Query in AQL
AQL 为所有支持的数据类型配备了多个函数。查询中的变量分配允许构建非常复杂的嵌套结构。这样,数据密集型操作会移至后端的データ比移至客户端(例如浏览器)更近的位置。为了理解这一点,让我们首先将任意持续时间(长度)添加到歌曲中。
首先,让我们从第一个函数开始,即 Update 函数 -
UPDATE { _key: "All_Mucked" }
WITH { length: 180 }
IN songs
我们可以看到,文档已按上述屏幕截图中所示进行编写。
现在让我们更新其他文档(歌曲)。
UPDATE { _key: "Affable_Balding" }
WITH { length: 200 }
IN songs
现在我们可以检查所有歌曲是否都有新属性 length -
FOR song IN songs
RETURN song
Output
[
{
"_key": "Air-Minded",
"_id": "songs/Air-Minded",
"_rev": "_VkC5lbS---",
"title": "Air-Minded Executive",
"lyricist": "Johnny Mercer",
"composer": "Bernie Hanighen",
"Year": 1940,
"length": 210
},
{
"_key": "Affable_Balding",
"_id": "songs/Affable_Balding",
"_rev": "_VkC4eM2---",
"title": "Affable Balding Me",
"lyricist": "Johnny Mercer",
"composer": "Robert Emmett Dolan",
"Year": 1950,
"length": 200
},
{
"_key": "All_Mucked",
"_id": "songs/All_Mucked",
"_rev": "_Vjah9Pu---",
"title": "All Mucked Up",
"lyricist": "Johnny Mercer",
"composer": "Andre Previn",
"Year": 1974,
"length": 180
},
{
"_key": "Accentchuate_The",
"_id": "songs/Accentchuate_The",
"_rev": "_VkC3WzW---",
"title": "Accentchuate The Politics",
"lyricist": "Johnny Mercer",
"composer": "Harold Arlen",
"Year": 1944,
"length": 190
}
]
为了说明 AQL 中的其他关键字(如 LET、FILTER、SORT 等)的用法,我们现在将歌曲的时长格式化为 mm:ss 格式。
Query
FOR song IN songs
FILTER song.length > 150
LET seconds = song.length % 60
LET minutes = FLOOR(song.length / 60)
SORT song.composer
RETURN
{
Title: song.title,
Composer: song.composer,
Duration: CONCAT_SEPARATOR(':',minutes, seconds)
}
这一次,我们将返回歌曲标题以及时长。 Return 函数可让你为每个输入文档创建一个新 JSON 对象以返回。
我们现在来讨论 AQL 数据库的“连接”功能。
让我们首先创建一个集合 composer_dob 。接下来,我们将通过在查询框中运行以下查询来创建四份包含作曲家的假设出生日期的文档 -
FOR dob IN [
{composer: "Bernie Hanighen", Year: 1909}
,
{composer: "Robert Emmett Dolan", Year: 1922}
,
{composer: "Andre Previn", Year: 1943}
,
{composer: "Harold Arlen", Year: 1910}
]
INSERT dob in composer_dob
为了突出它与 SQL 的相似性,我们在 AQL 中提供了一个嵌套的 FOR-loop 查询,导致了 REPLACE 操作,它首先在内部循环中迭代,遍历所有作曲家的 dob,然后遍历所有关联的歌曲,创建包含属性 song_with_composer_key 的新文档,而不是属性 song 。
查询如下 -
FOR s IN songs
FOR c IN composer_dob
FILTER s.composer == c.composer
LET song_with_composer_key = MERGE(
UNSET(s, 'composer'),
{composer_key:c._key}
)
REPLACE s with song_with_composer_key IN songs
现在让我们再次运行查询 FOR song IN songs RETURN song ,看看歌曲集合如何改变。
Output
[
{
"_key": "Air-Minded",
"_id": "songs/Air-Minded",
"_rev": "_Vk8kFoK---",
"Year": 1940,
"composer_key": "5501",
"length": 210,
"lyricist": "Johnny Mercer",
"title": "Air-Minded Executive"
},
{
"_key": "Affable_Balding",
"_id": "songs/Affable_Balding",
"_rev": "_Vk8kFoK--_",
"Year": 1950,
"composer_key": "5505",
"length": 200,
"lyricist": "Johnny Mercer",
"title": "Affable Balding Me"
},
{
"_key": "All_Mucked",
"_id": "songs/All_Mucked",
"_rev": "_Vk8kFoK--A",
"Year": 1974,
"composer_key": "5507",
"length": 180,
"lyricist": "Johnny Mercer",
"title": "All Mucked Up"
},
{
"_key": "Accentchuate_The",
"_id": "songs/Accentchuate_The",
"_rev": "_Vk8kFoK--B",
"Year": 1944,
"composer_key": "5509",
"length": 190,
"lyricist": "Johnny Mercer",
"title": "Accentchuate The Politics"
}
]
以上查询完成了数据迁移过程,向每首歌曲添加 composer_key 。
现在,下一个查询仍然是一个嵌套的 FOR-loop 查询,但这一次却导致了连接操作,将关联作曲家的姓名(通过 composer_key
协助选取)添加到每首歌曲中 -
FOR s IN songs
FOR c IN composer_dob
FILTER c._key == s.composer_key
RETURN MERGE(s,
{ composer: c.composer }
)
Output
[
{
"Year": 1940,
"_id": "songs/Air-Minded",
"_key": "Air-Minded",
"_rev": "_Vk8kFoK---",
"composer_key": "5501",
"length": 210,
"lyricist": "Johnny Mercer",
"title": "Air-Minded Executive",
"composer": "Bernie Hanighen"
},
{
"Year": 1950,
"_id": "songs/Affable_Balding",
"_key": "Affable_Balding",
"_rev": "_Vk8kFoK--_",
"composer_key": "5505",
"length": 200,
"lyricist": "Johnny Mercer",
"title": "Affable Balding Me",
"composer": "Robert Emmett Dolan"
},
{
"Year": 1974,
"_id": "songs/All_Mucked",
"_key": "All_Mucked",
"_rev": "_Vk8kFoK--A",
"composer_key": "5507",
"length": 180,
"lyricist": "Johnny Mercer",
"title": "All Mucked Up",
"composer": "Andre Previn"
},
{
"Year": 1944,
"_id": "songs/Accentchuate_The",
"_key": "Accentchuate_The",
"_rev": "_Vk8kFoK--B",
"composer_key": "5509",
"length": 190,
"lyricist": "Johnny Mercer",
"title": "Accentchuate The Politics",
"composer": "Harold Arlen"
}
]