ArangoDB - 使用 AQL 查询数据

在本章中,我们将讨论如何使用 AQL 查询数据。 我们已经在前面的章节中讨论过 ArangoDB 开发了自己的查询语言,它的名称是 AQL。

现在让我们开始与 AQL 交互。 如下图所示,在 Web 界面中,按导航栏顶部的 AQL 编辑器 选项卡。 将出现一个空白查询编辑器。

需要时,您可以通过单击右上角的"查询"或"结果"选项卡,从结果视图切换到编辑器,反之亦然,如下图所示 −

从结果视图切换到编辑器

除其他功能外,编辑器还具有语法突出显示、撤消/重做功能和查询保存功能。 详细的参考可以查看官方文档。 我们将重点介绍 AQL 查询编辑器的一些基本和常用功能。

AQL 基础知识

在 AQL 中,查询代表要实现的最终结果,而不是实现最终结果的过程。 此功能通常称为语言的声明性属性。 此外,AQL 可以查询也可以修改数据,因此可以通过结合这两个过程来创建复杂的查询。

请注意,AQL 完全符合 ACID 标准。 读取或修改查询要么全部结束,要么根本不结束。 即使读取文档的数据也会以一致的数据单位完成。

我们将两首新歌曲添加到我们已经创建的歌曲集中。 您可以复制以下查询并将其粘贴到 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

按左下角的"执行"按钮。

它将在 songs 集合中写入两个新文档。

此查询描述了 FOR 循环在 AQL 中的工作原理; 它迭代 JSON 编码文档列表,对集合中的每个文档执行编码操作。 不同的操作可以是创建新结构、过滤、选择文档、修改或将文档插入数据库(请参阅即时示例)。 本质上,AQL 可以高效地执行 CRUD 操作。

要查找数据库中的所有歌曲,让我们再次运行以下查询,相当于 SQL 类型数据库的 SELECT * FROMongs (因为编辑器会记住最后一个查询, 按*New*按钮清理编辑器) −

FOR song IN songs
RETURN song

结果集将显示迄今为止保存在歌曲集合中的歌曲列表,如下面的屏幕截图所示。

歌曲列表

可以将FILTER、SORTLIMIT等操作添加到For循环主体中以缩小结果范围并对其进行排序。

FOR song IN songs
FILTER song.Year > 1940
RETURN song

上述查询将在"结果"选项卡中给出 1940 年之后创建的歌曲(见下图)。

查询 Year_1940 之后创建的歌曲

本示例中使用了文档键,但也可以使用任何其他属性作为过滤的等效属性。 由于保证文档键是唯一的,因此不会有超过一个文档与此过滤器匹配。 对于其他属性,情况可能并非如此。 要返回活跃用户的子集(由称为状态的属性确定),按名称升序排序,我们使用以下语法 −

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

运行正确的查询

AQL 中的复杂查询

AQL 配备了适用于所有支持的数据类型的多种函数。 查询中的变量分配允许构建非常复杂的嵌套结构。 这样,数据密集型操作就更接近后端的数据,而不是客户端(例如浏览器)。 为了理解这一点,让我们首先向歌曲添加任意持续时间(长度)。

让我们从第一个函数开始,即 Update 函数 −

UPDATE { _key: "All_Mucked" }
WITH { length: 180 }
IN songs

AQL 中的复杂查询

我们可以看到已经写入了一个文档,如上面的截图所示。

现在让我们也更新其他文档(歌曲)。

UPDATE { _key: "Affable_Balding" }
WITH { length: 200 }
IN songs

我们现在可以检查所有歌曲是否都有一个新属性长度

FOR song IN songs
RETURN song

输出

[
   {
      "_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 格式。

查询

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

AQL 2 中的复杂查询

这次我们将返回歌曲标题和时长。 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

Composer DOB

为了突出与 SQL 的相似性,我们在 AQL 中提出了一个嵌套的 FOR 循环查询,导致 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

带有 composer_key 的歌曲

现在让我们再次运行查询FOR歌曲IN歌曲RETURN歌曲来查看歌曲集合发生了怎样的变化。

输出

[
   {
      "_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 循环查询,但这次导致 Join 操作,将关联的作曲家姓名(在 `composer_key` 的帮助下选择)添加到每首歌曲中 −

FOR s IN songs
FOR c IN composer_dob
FILTER c._key == s.composer_key
RETURN MERGE(s,
{ composer: c.composer }
)

输出

[
   {
      "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"
   }
]

为每首歌曲添加 Composer_Key