ArangoDB - 快速指南
ArangoDB - 多模型第一数据库
ArangoDB 被其开发人员誉为原生多模型数据库。这与其他 NoSQL 数据库不同。在此数据库中,数据可以存储为文档、键/值对或图形。使用单一声明性查询语言,可以访问您的任何或所有数据。此外,不同的模型可以组合在一个查询中。而且,由于其多模型风格,人们可以制作精益应用程序,这些应用程序可以使用三种数据模型中的任何一种或全部进行水平扩展。
分层与本机多模型数据库
在本节中,我们将强调本机多模型数据库和分层多模型数据库之间的关键区别。
许多数据库供应商将他们的产品称为“多模型”,但向键/值或文档存储添加图形层并不符合本机多模型的条件。
使用 ArangoDB,相同的核心和相同的查询语言,可以将不同的数据模型和功能组合在一个查询中,正如我们在上一节中已经说过的那样。在ArangoDB中,数据模型之间没有“切换”,也没有将数据从A转移到B来执行查询。与“分层”方法相比,它为 ArangoDB 带来了性能优势。
对多模式数据库的需求
解释[Fowler]的基本思想使我们认识到对持久层的不同部分使用各种适当的数据模型的好处,该层是更大的软件架构的一部分。
据此,例如,可以使用关系数据库来保存结构化的表格数据;非结构化、类对象数据的文档存储;哈希表的键/值存储;以及一个用于高度链接的参考数据的图形数据库。
然而,这种方法的传统实现将导致在同一项目中使用多个数据库。它可能会导致一些操作摩擦(更复杂的部署、更频繁的升级)以及数据一致性和重复问题。
统一三种数据模型的数据后,下一个挑战是设计和实现一种通用查询语言,允许数据管理员表达各种查询,例如文档查询、键/值查找、图形查询和任意组合这些。
通过图形查询,我们指的是涉及图论考虑的查询。特别是,这些可能涉及来自边缘的特定连接特征。例如,ShortestPath、GraphTraversal和Neighbors。
图表非常适合作为关系的数据模型。在许多现实世界的案例中,例如社交网络、推荐系统等,一个非常自然的数据模型是图。它捕获关系并可以保存每个边和每个顶点的标签信息。此外,JSON 文档非常适合存储此类顶点和边数据。
ArangoDB ─ 特点
ArangoDB 有各种值得注意的功能。我们将重点介绍以下突出特点 -
- 多模型范式
- 酸性性质
- HTTP API
ArangoDB 支持所有流行的数据库模型。以下是 ArangoDB 支持的一些模型 -
- 文档模型
- 键/值模型
- 图模型
单一查询语言足以从数据库中检索数据
Atomics性、一致性、隔离性和持久性(ACID)这四个属性描述了数据库事务的保证。ArangoDB 支持符合 ACID 的事务。
ArangoDB 允许客户端(例如浏览器)通过 HTTP API 与数据库交互,该 API 是面向资源的并且可通过 JavaScript 进行扩展。
ArangoDB - 优点
以下是使用 ArangoDB 的优点 -
合并
作为原生多模型数据库,ArangoDB 无需部署多个数据库,从而减少了组件数量及其维护。因此,它降低了应用程序的技术堆栈复杂性。除了巩固您的整体技术需求之外,这种简化还可以降低总拥有成本并提高灵活性。
简化的性能扩展
随着应用程序随着时间的推移不断增长,ArangoDB 可以通过独立扩展不同的数据模型来满足不断增长的性能和存储需求。由于 ArangoDB 可以垂直和水平扩展,因此,如果您的性能需要降低(故意的、期望的减速),您的后端系统可以轻松地缩小规模,以节省硬件和运营成本。
降低操作复杂性
多语言持久性的法令是为您承担的每项工作使用最好的工具。某些任务需要文档数据库,而其他任务可能需要图形数据库。由于使用单一模型数据库,可能会带来多种操作挑战。集成单一模型数据库本身就是一项艰巨的工作。但最大的挑战是在独立的、不相关的数据库系统之间构建一个具有数据一致性和容错能力的大型内聚结构。这可能被证明几乎是不可能的。
多语言持久性可以使用本机多模型数据库来处理,因为它允许轻松拥有多语言数据,但同时在容错系统上保持数据一致性。借助 ArangoDB,我们可以使用正确的数据模型来完成复杂的工作。
数据一致性强
如果使用多个单模型数据库,数据一致性可能会成为一个问题。这些数据库并不是为了相互通信而设计的,因此需要实现某种形式的事务功能以保持不同模型之间的数据一致。
ArangoDB 支持 ACID 事务,通过单个后端管理您的不同数据模型,在单个实例上提供强一致性,并在集群模式下运行时提供Atomics操作。
容错能力
构建具有许多不相关组件的容错系统是一个挑战。当使用集群时,这一挑战变得更加复杂。使用不同的技术和/或技术堆栈来部署和维护此类系统需要专业知识。此外,集成多个独立运行的子系统会造成巨大的工程和运营成本。
作为一个整合的技术堆栈,多模型数据库提供了一个优雅的解决方案。ArangoDB 旨在支持具有不同数据模型的现代模块化架构,也适用于集群使用。
降低总拥有成本
每种数据库技术都需要供应商提供的持续维护、错误修复补丁和其他代码更改。采用多模型数据库只需消除设计应用程序时数据库技术的数量即可显着降低相关的维护成本。
交易
在多台机器上提供事务保证是一个真正的挑战,很少有 NoSQL 数据库能够提供这些保证。作为原生多模型,ArangoDB 强加事务来保证数据一致性。
基本概念和术语
在本章中,我们将讨论 ArangoDB 的基本概念和术语。了解与我们正在处理的技术主题相关的基本术语非常重要。
ArangoDB 的术语如下:
- 文档
- 收藏
- 集合标识符
- 收藏名称
- 数据库
- 数据库名称
- 数据库组织
从数据模型的角度来看,ArangoDB可以被认为是一个面向文档的数据库,因为文档的概念就是后者的数学思想。面向文档的数据库是NoSQL数据库的主要类别之一。
层次结构如下:文档被分组为集合,集合存在于数据库内
显然,Identifier 和 Name 是集合和数据库的两个属性。
通常,存储在文档集合中的两个文档(顶点)通过存储在边集合中的文档(边)链接。这是ArangoDB的图数据模型。它遵循有向标记图的数学概念,只是边不仅有标签,而且是成熟的文档。
熟悉了该数据库的核心术语后,我们开始了解 ArangoDB 的图数据模型。在该模型中,存在两种类型的集合:文档集合和边集合。边缘集合存储文档,还包含两个特殊属性:第一个是_from属性,第二个是_to属性。这些属性用于创建图数据库必需的文档之间的边(关系)。在图的上下文中,文档集合也称为顶点集合(请参阅任何图论书籍)。
现在让我们看看数据库有多重要。它们很重要,因为集合存在于数据库内部。在一个 ArangoDB 实例中,可以有一个或多个数据库。不同的数据库通常用于多租户设置,因为其中的不同数据集(集合、文档等)彼此隔离。默认数据库_system很特殊,因为它无法删除。用户在此数据库中进行管理,其凭据对于服务器实例的所有数据库都有效。
ArangoDB - 系统要求
在本章中,我们将讨论 ArangoDB 的系统要求。
ArangoDB 的系统要求如下:
- 安装了 Ubuntu 的 VPS 服务器
- 内存:1GB;中央处理器:2.2GHz
对于本教程中的所有命令,我们使用了 RAM 1GB 的 Ubuntu 16.04 (xenial) 实例,其中一个 cpu 的处理能力为 2.2 GHz。本教程中的所有 arangosh 命令均针对 ArangoDB 版本 3.1.27 进行了测试。
如何安装ArangoDB?
在本节中,我们将了解如何安装 ArangoDB。ArangoDB 是为许多操作系统和发行版预先构建的。有关更多详细信息,请参阅 ArangoDB 文档。如前所述,在本教程中我们将使用 Ubuntu 16.04x64。
第一步是下载其存储库的公钥 -
# wget https://www.arangodb.com/repositories/arangodb31/ xUbuntu_16.04/Release.key
输出
--2017-09-03 12:13:24-- https://www.arangodb.com/repositories/arangodb31/xUbuntu_16.04/Release.key Resolving https://www.arangodb.com/ (www.arangodb.com)... 104.25.1 64.21, 104.25.165.21, 2400:cb00:2048:1::6819:a415, ... Connecting to https://www.arangodb.com/ (www.arangodb.com)|104.25. 164.21|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 3924 (3.8K) [application/pgpkeys] Saving to: ‘Release.key’ Release.key 100%[===================>] 3.83K - .-KB/s in 0.001s 2017-09-03 12:13:25 (2.61 MB/s) - ‘Release.key’ saved [39 24/3924]
重要的一点是,您应该看到在输出末尾保存的Release.key 。
让我们使用以下代码行安装保存的密钥 -
# sudo apt-key add Release.key
输出
OK
运行以下命令添加 apt 存储库并更新索引 -
# sudo apt-add-repository 'deb https://www.arangodb.com/repositories/arangodb31/xUbuntu_16.04/ /' # sudo apt-get update
最后一步,我们可以安装 ArangoDB -
# sudo apt-get install arangodb3
输出
Reading package lists... Done Building dependency tree Reading state information... Done The following package was automatically installed and is no longer required: grub-pc-bin Use 'sudo apt autoremove' to remove it. The following NEW packages will be installed: arangodb3 0 upgraded, 1 newly installed, 0 to remove and 17 not upgraded. Need to get 55.6 MB of archives. After this operation, 343 MB of additional disk space will be used.
按Enter键。现在安装 ArangoDB 的过程将开始 -
Get:1 https://www.arangodb.com/repositories/arangodb31/xUbuntu_16.04 arangodb3 3.1.27 [55.6 MB] Fetched 55.6 MB in 59s (942 kB/s) Preconfiguring packages ... Selecting previously unselected package arangodb3. (Reading database ... 54209 files and directories currently installed.) Preparing to unpack .../arangodb3_3.1.27_amd64.deb ... Unpacking arangodb3 (3.1.27) ... Processing triggers for systemd (229-4ubuntu19) ... Processing triggers for ureadahead (0.100.0-19) ... Processing triggers for man-db (2.7.5-1) ... Setting up arangodb3 (3.1.27) ... Database files are up-to-date.
当 ArangoDB 的安装即将完成时,会出现以下屏幕 -
在这里,您将被要求提供 ArangoDB root用户的密码。仔细记下来。
当出现以下对话框时选择是选项 -
当您在上面的对话框中单击“是”时,将出现以下对话框。单击此处是。
您还可以使用以下命令检查 ArangoDB 的状态 -
# sudo systemctl status arangodb3
输出
arangodb3.service - LSB: arangodb Loaded: loaded (/etc/init.d/arangodb3; bad; vendor pre set: enabled) Active: active (running) since Mon 2017-09-04 05:42:35 UTC; 4min 46s ago Docs: man:systemd-sysv-generator(8) Process: 2642 ExecStart=/etc/init.d/arangodb3 start (code = exited, status = 0/SUC Tasks: 22 Memory: 158.6M CPU: 3.117s CGroup: /system.slice/arangodb3.service ├─2689 /usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /va └─2690 /usr/sbin/arangod --uid arangodb --gid arangodb --pid-file /va Sep 04 05:42:33 ubuntu-512 systemd[1]: Starting LSB: arangodb... Sep 04 05:42:33 ubuntu-512 arangodb3[2642]: * Starting arango database server a Sep 04 05:42:35 ubuntu-512 arangodb3[2642]: {startup} starting up in daemon mode Sep 04 05:42:35 ubuntu-512 arangodb3[2642]: changed working directory for child Sep 04 05:42:35 ubuntu-512 arangodb3[2642]: ...done. Sep 04 05:42:35 ubuntu-512 systemd[1]: StartedLSB: arang odb. Sep 04 05:46:59 ubuntu-512 systemd[1]: Started LSB: arangodb. lines 1-19/19 (END)
ArangoDB 现在可以使用了。
要调用 arangosh 终端,请在终端中键入以下命令 -
# arangosh
输出
Please specify a password:
提供安装时创建的root密码 -
_ __ _ _ __ __ _ _ __ __ _ ___ | | / | '__/ _ | ’ \ / ` |/ _ / | ’ | (| | | | (| | | | | (| | () _ \ | | | _,|| _,|| ||_, |_/|/| || |__/
arangosh (ArangoDB 3.1.27 [linux] 64bit, using VPack 0.1.30, ICU 54.1, V8 5.0.71.39, OpenSSL 1.0.2g 1 Mar 2016) Copyright (c) ArangoDB GmbH Pretty printing values. Connected to ArangoDB 'http+tcp://127.0.0.1:8529' version: 3.1.27 [server], database: '_system', username: 'root' Please note that a new minor version '3.2.2' is available Type 'tutorial' for a tutorial or 'help' to see common examples 127.0.0.1:8529@_system> exit
要从 ArangoDB 注销,请输入以下命令 -
127.0.0.1:8529@_system> exit
输出
Uf wiederluege! Na shledanou! Auf Wiedersehen! Bye Bye! Adiau! ¡Hasta luego! Εις το επανιδείν! להתראות ! Arrivederci! Tot ziens! Adjö! Au revoir! さようなら До свидания! Até Breve! !خداحافظ
ArangoDB - 命令行
在本章中,我们将讨论 Arangosh 如何作为 ArangoDB 的命令行工作。我们将从学习如何添加数据库用户开始。
注意- 请记住数字键盘可能无法在 Arangosh 上使用。
让我们假设用户是“harry”,密码是“hpwdb”。
127.0.0.1:8529@_system> require("org/arangodb/users").save("harry", "hpwdb");
输出
{ "user" : "harry", "active" : true, "extra" : {}, "changePassword" : false, "code" : 201 }
ArangoDB - Web 界面
在本章中,我们将学习如何启用/禁用身份验证,以及如何将 ArangoDB 绑定到公共网络接口。
# arangosh --server.endpoint tcp://127.0.0.1:8529 --server.database "_system"
它会提示您输入之前保存的密码 -
Please specify a password:
使用您在配置中为 root 创建的密码。
您还可以使用curl来检查您是否确实获得了需要身份验证的请求的HTTP 401(未经授权)服务器响应 -
# curl --dump - http://127.0.0.1:8529/_api/version
输出
HTTP/1.1 401 Unauthorized X-Content-Type-Options: nosniff Www-Authenticate: Bearer token_type = "JWT", realm = "ArangoDB" Server: ArangoDB Connection: Keep-Alive Content-Type: text/plain; charset = utf-8 Content-Length: 0
为了避免在学习过程中每次都输入密码,我们将禁用身份验证。为此,打开配置文件 -
# vim /etc/arangodb3/arangod.conf
如果代码不正确可见,您应该更改颜色方案。
:colorscheme desert
将身份验证设置为 false,如下面的屏幕截图所示。
重新启动服务 -
# service arangodb3 restart
将身份验证设置为 false 后,您将能够登录(在本例中使用 root 或像Harry这样的创建用户),而无需在请指定密码中输入任何密码。
让我们检查身份验证关闭时的api版本 -
# curl --dump - http://127.0.0.1:8529/_api/version
输出
HTTP/1.1 200 OK X-Content-Type-Options: nosniff Server: ArangoDB Connection: Keep-Alive Content-Type: application/json; charset=utf-8 Content-Length: 60 {"server":"arango","version":"3.1.27","license":"community"}
ArangoDB - 示例案例场景
在本章中,我们将考虑两个示例场景。这些示例更容易理解,并将帮助我们理解 ArangoDB 功能的工作方式。
为了演示 API,ArangoDB 预加载了一组易于理解的图表。有两种方法可以在 ArangoDB 中创建这些图的实例 -
- 在 Web 界面的创建图形窗口中添加示例选项卡,
- 或者在 Arangosh 中加载模块@arangodb/graph-examples/example-graph。
首先,让我们借助 Web 界面加载图表。为此,启动 Web 界面并单击图表选项卡。
将出现“创建图表”对话框。该向导包含两个选项卡 -示例和图表。图表选项卡默认打开;假设我们要创建一个新图,它将询问该图的名称和其他定义。
现在,我们将上传已经创建的图表。为此,我们将选择“示例”选项卡。
我们可以看到三个示例图。选择Knows_Graph并单击绿色按钮“创建”。
创建它们后,您可以在网络界面中检查它们 - 该界面用于创建下面的图片。
知道图
现在让我们看看Knows_Graph是如何工作的。选择Knows_Graph,它将获取图形数据。
Knows_Graph 由通过一个已知的边集合连接的一个顶点集合组成。它将包含五个人 Alice、Bob、Charlie、Dave 和 Eve 作为顶点。我们将有以下直接关系
Alice knows Bob Bob knows Charlie Bob knows Dave Eve knows Alice Eve knows Bob
如果单击一个节点(顶点),例如“bob”,它将显示 ID (persons/bob) 属性名称。
单击任何边缘时,它将显示 ID (knows/4590) 属性。
这就是我们创建它、检查它的顶点和边的方式。
让我们添加另一个图表,这次使用 Arangosh。为此,我们需要在 ArangoDB 配置文件中包含另一个端点。
如何添加多个端点
打开配置文件 -
# vim /etc/arangodb3/arangod.conf
添加另一个端点,如下面的终端屏幕截图所示。
重新启动 ArangoDB -
# service arangodb3 restart
发射 Arangosh -
# arangosh Please specify a password: _ __ _ _ __ __ _ _ __ __ _ ___ ___| |__ / _` | '__/ _` | '_ \ / _` |/ _ \/ __| '_ \ | (_| | | | (_| | | | | (_| | (_) \__ \ | | | \__,_|_| \__,_|_| |_|\__, |\___/|___/_| |_| |___/ arangosh (ArangoDB 3.1.27 [linux] 64bit, using VPack 0.1.30, ICU 54.1, V8 5.0.71.39, OpenSSL 1.0.2g 1 Mar 2016) Copyright (c) ArangoDB GmbH Pretty printing values. Connected to ArangoDB 'http+tcp://127.0.0.1:8529' version: 3.1.27 [server], database: '_system', username: 'root' Please note that a new minor version '3.2.2' is available Type 'tutorial' for a tutorial or 'help' to see common examples 127.0.0.1:8529@_system>
社交图谱
现在让我们了解什么是 Social_Graph 以及它是如何工作的。该图显示了一组人及其关系 -
此示例将女性和男性作为两个顶点集合(女性和男性)中的顶点。边是关系边集合中它们的连接。我们已经描述了如何使用 Arangosh 创建此图。读者可以解决它并探索它的属性,就像我们对 Knows_Graph 所做的那样。
ArangoDB - 数据模型和建模
在本章中,我们将重点关注以下主题 -
- 数据库交互
- 数据模型
- 数据检索
ArangoDB 支持基于文档的数据模型以及基于图形的数据模型。让我们首先描述基于文档的数据模型。
ArangoDB 的文档与 JSON 格式非常相似。文档中包含零个或多个属性,每个属性都附加一个值。值可以是Atomics类型(例如数字、布尔值或 null、文字字符串),也可以是复合数据类型(例如嵌入式文档/对象或数组)。数组或子对象可能由这些数据类型组成,这意味着单个文档可以表示重要的数据结构。
在层次结构中,文档被排列成集合,其中可能不包含文档(理论上)或包含多个文档。人们可以将文档与行进行比较,将集合与表进行比较(这里的表和行是指关系数据库管理系统 - RDBMS 中的表和行)。
但是,在 RDBMS 中,定义列是将记录存储到表中的先决条件,这些定义称为模式。然而,作为一项新颖的功能,ArangoDB 是无模式的——没有先验的理由来指定文档将具有哪些属性。
与 RDBMS 不同的是,每个文档的结构方式都可以与另一个文档完全不同。这些文档可以一起保存在一个集合中。实际上,集合中的文档之间可能存在共同特征,但是数据库系统(即 ArangoDB 本身)并不将您绑定到特定的数据结构。
现在我们将尝试理解ArangoDB的[图数据模型],它需要两种集合——第一种是文档集合(在群论语言中称为顶点集合),第二种是边集合。这两种类型之间存在细微的差别。边缘集合也存储文档,但它们的特点是包含两个独特的属性:_from和_to,用于创建文档之间的关系。实际上,一个文档(读取边)链接两个文档(读取顶点),两个文档都存储在各自的集合中。该架构源自带标签的有向图的图论概念,不包括不仅可以具有标签,而且本身可以是完整的 JSON 文档的边。
为了计算新数据、删除文档或操作它们,需要使用查询,根据给定的条件选择或过滤文档。无论是简单的“示例查询”还是复杂的“连接”,查询都使用 AQL(ArangoDB 查询语言)进行编码。
ArangoDB - 数据库方法
在本章中,我们将讨论 ArangoDB 中的不同数据库方法。
首先,让我们获取数据库的属性 -
- 姓名
- ID
- 小路
首先,我们调用 Arangosh。一旦调用 Arangosh,我们将列出迄今为止创建的数据库 -
我们将使用以下代码行来调用 Arangosh -
127.0.0.1:8529@_system> db._databases()
输出
[ "_system", "song_collection" ]
我们看到两个数据库,一个是默认创建的_system ,第二个是我们创建的song_collection 。
现在让我们使用以下代码行转移到 Song_collection 数据库 -
127.0.0.1:8529@_system> db._useDatabase("song_collection")
输出
true 127.0.0.1:8529@song_collection>
我们将探索 Song_collection 数据库的属性。
为了找到名字
我们将使用以下代码行来查找名称。
127.0.0.1:8529@song_collection> db._name()
输出
song_collection
查找 id -
我们将使用以下代码行来查找 id。
127.0.0.1:8529@song_collection> db._id()
输出
4838
找到路径 -
我们将使用以下代码行来查找路径。
127.0.0.1:8529@song_collection> db._path()
输出
/var/lib/arangodb3/databases/database-4838
现在让我们使用以下代码行检查我们是否在系统数据库中 -
127.0.0.1:8529@song_collection&t; db._isSystem()
输出
false
这意味着我们不在系统数据库中(因为我们已经创建并转移到了song_collection)。下面的屏幕截图将帮助您理解这一点。
要获得特定的收藏,请说出歌曲 -
我们将使用以下代码行来获取特定的集合。
127.0.0.1:8529@song_collection> db._collection("songs")
输出
[ArangoCollection 4890, "songs" (type document, status loaded)]
该代码行返回单个集合。
让我们在后续章节中讨论数据库操作的要点。
ArangoDB - Crud 操作
在本章中,我们将学习 Arangosh 的不同操作。
以下是 Arangosh 可能进行的操作 -
- 创建文档集合
- 创建文档
- 阅读文档
- 更新文件
让我们从创建一个新数据库开始。我们将使用以下代码行创建一个新数据库 -
127.0.0.1:8529@_system> db._createDatabase("song_collection") true
以下代码行将帮助您转移到新数据库 -
127.0.0.1:8529@_system> db._useDatabase("song_collection") true
提示将转变为“@@song_collection”
127.0.0.1:8529@song_collection>
从这里我们将学习 CRUD 操作。让我们在新数据库中创建一个集合 -
127.0.0.1:8529@song_collection> db._createDocumentCollection('songs')
输出
[ArangoCollection 4890, "songs" (type document, status loaded)] 127.0.0.1:8529@song_collection>
让我们向“歌曲”集合中添加一些文档(JSON 对象)。
我们通过以下方式添加第一个文档 -
127.0.0.1:8529@song_collection> db.songs.save({title: "A Man's Best Friend", lyricist: "Johnny Mercer", composer: "Johnny Mercer", Year: 1950, _key: "A_Man"})
输出
{ "_id" : "songs/A_Man", "_key" : "A_Man", "_rev" : "_VjVClbW---" }
让我们将其他文档添加到数据库中。这将有助于我们了解查询数据的过程。您可以复制这些代码并将其粘贴到 Arangosh 中以模拟该过程 -
127.0.0.1:8529@song_collection> db.songs.save( { title: "Accentchuate The Politics", lyricist: "Johnny Mercer", composer: "Harold Arlen", Year: 1944, _key: "Accentchuate_The" } ) { "_id" : "songs/Accentchuate_The", "_key" : "Accentchuate_The", "_rev" : "_VjVDnzO---" } 127.0.0.1:8529@song_collection> db.songs.save( { title: "Affable Balding Me", lyricist: "Johnny Mercer", composer: "Robert Emmett Dolan", Year: 1950, _key: "Affable_Balding" } ) { "_id" : "songs/Affable_Balding", "_key" : "Affable_Balding", "_rev" : "_VjVEFMm---" }
如何阅读文档
_key或文档句柄可用于检索文档。如果不需要遍历集合本身,请使用文档句柄。如果您有收藏,文档功能很容易使用 -
127.0.0.1:8529@song_collection> db.songs.document("A_Man"); { "_key" : "A_Man", "_id" : "songs/A_Man", "_rev" : "_VjVClbW---", "title" : "A Man's Best Friend", "lyricist" : "Johnny Mercer", "composer" : "Johnny Mercer", "Year" : 1950 }
如何更新文档
有两个选项可用于更新保存的数据 -替换和更新。
更新函数修补文档,将其与给定的属性合并。另一方面,替换功能将用新文档替换以前的文档。即使提供完全不同的属性,替换仍然会发生。我们将首先观察非破坏性更新,更新歌曲中的属性 Production` -
127.0.0.1:8529@song_collection> db.songs.update("songs/A_Man",{production: "Top Banana"});
输出
{ "_id" : "songs/A_Man", "_key" : "A_Man", "_rev" : "_VjVOcqe---", "_oldRev" : "_VjVClbW---" }
现在让我们看看更新后的歌曲的属性 -
127.0.0.1:8529@song_collection> db.songs.document('A_Man');
输出
{ "_key" : "A_Man", "_id" : "songs/A_Man", "_rev" : "_VjVOcqe---", "title" : "A Man's Best Friend", "lyricist" : "Johnny Mercer", "composer" : "Johnny Mercer", "Year" : 1950, "production" : "Top Banana" }
使用更新功能可以轻松更新大型文档,尤其是当属性很少时。
相反,替换功能将废除您在同一文档中使用它的数据。
127.0.0.1:8529@song_collection> db.songs.replace("songs/A_Man",{production: "Top Banana"});
现在让我们检查一下我们刚刚使用以下代码行更新的歌曲 -
127.0.0.1:8529@song_collection> db.songs.document('A_Man');
输出
{ "_key" : "A_Man", "_id" : "songs/A_Man", "_rev" : "_VjVRhOq---", "production" : "Top Banana" }
现在,您可以观察到该文档不再具有原始数据。
如何删除文档
删除函数与文档句柄结合使用,以从集合中删除文档 -
127.0.0.1:8529@song_collection> db.songs.remove('A_Man');
现在让我们使用以下代码行检查刚刚删除的歌曲属性 -
127.0.0.1:8529@song_collection> db.songs.document('A_Man');
我们将得到如下所示的异常错误作为输出 -
JavaScript exception in file '/usr/share/arangodb3/js/client/modules/@arangodb/arangosh.js' at 97,7: ArangoError 1202: document not found ! throw error; ! ^ stacktrace: ArangoError: document not found at Object.exports.checkRequestResult (/usr/share/arangodb3/js/client/modules/@arangodb/arangosh.js:95:21) at ArangoCollection.document (/usr/share/arangodb3/js/client/modules/@arangodb/arango-collection.js:667:12) at <shell command>:1:10
使用 Web 界面进行 Crud 操作
在上一章中,我们学习了如何使用命令行 Arangosh 对文档执行各种操作。我们现在将学习如何使用 Web 界面执行相同的操作。首先,将以下地址 - http://your_server_ip:8529/_db/song_collection/_admin/aardvark/index.html#login 放入浏览器的地址栏中。您将被引导至以下登录页面。
现在,输入用户名和密码。
如果成功,将出现以下屏幕。我们需要选择要使用的数据库,_system数据库是默认数据库。让我们选择Song_collection数据库,然后单击绿色选项卡 -
创建集合
在本节中,我们将学习如何创建集合。按顶部导航栏中的“集合”选项卡。
我们的命令行添加的歌曲集合是可见的。单击该按钮将显示条目。我们现在将使用网络界面添加艺术家收藏。我们和 Arangosh 一起创作的精选歌曲已经在那里了。在“名称”字段中,在出现的“新建收藏”对话框中写入艺术家。可以安全地忽略高级选项,并且默认集合类型(即文档)就可以了。
单击“保存”按钮将最终创建集合,现在这两个集合将在此页面上可见。
用文档填充新创建的集合
单击艺术家收藏后,您将看到一个空收藏-
要添加文档,您需要单击右上角的+号。当系统提示您输入_key时,请输入Affable_Balding作为密钥。
现在,将出现一个表单来添加和编辑文档的属性。添加属性有两种方法:图形和树。图形方式很直观,但速度很慢,因此,我们将切换到代码视图,使用树下拉菜单选择它 -
为了使该过程更容易,我们创建了 JSON 格式的示例数据,您可以将其复制然后粘贴到查询编辑器区域 -
{“艺术家”:“约翰尼·默瑟”,“标题”:“和蔼可亲的秃头我”,“作曲家”:“罗伯特·埃米特·多兰”,“年份”:1950}
(注意:只能使用一对花括号;请参见下面的屏幕截图)
您可以看到我们在代码视图模式下引用了键和值。现在,单击“保存”。成功完成后,页面上会立即出现绿色闪烁。
如何阅读文档
要阅读文档,请返回“集合”页面。
当单击艺术家收藏时,会出现一个新条目。
如何更新文档
编辑文档中的条目很简单;您只需在文档概述中单击要编辑的行即可。这里将再次显示与创建新文档时相同的查询编辑器。
删除文档
您可以通过按“-”图标删除文档。每个文档行末尾都有此标志。它会提示您确认以避免不安全删除。
此外,对于特定集合, “集合概览”页面还存在其他操作,如过滤文档、管理索引、导入数据等。
在后续章节中,我们将讨论 Web 界面的一个重要功能,即 AQL 查询编辑器。
使用 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
按左下角的执行按钮。
它将在歌曲集中写入两个新文档。
此查询描述了 FOR 循环在 AQL 中的工作原理;它迭代 JSON 编码文档列表,对集合中的每个文档执行编码操作。不同的操作可以是创建新结构、过滤、选择文档、修改或将文档插入数据库(请参阅即时示例)。本质上,AQL 可以高效地执行 CRUD 操作。
要查找数据库中的所有歌曲,让我们再次运行以下查询,相当于SQL 类型数据库的SELECT * FROM 歌曲(因为编辑器会记住最后一个查询,请按*New*按钮来清理编辑器) −
FOR song IN songs RETURN song
结果集将显示迄今为止保存在歌曲集中的歌曲列表,如下面的屏幕截图所示。
可以将FILTER、SORT和LIMIT等操作添加到For 循环体中以缩小结果范围并对其进行排序。
FOR song IN songs FILTER song.Year > 1940 RETURN song
上述查询将在“结果”选项卡中给出 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
我们可以看到已经写入了一份文档,如上图所示。
现在让我们也更新其他文档(歌曲)。
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) }
这次我们将返回歌曲标题和时长。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 循环查询,导致 REPLACE 操作,首先在内循环中迭代,遍历所有作曲家的 dob,然后遍历所有关联的歌曲,创建一个包含以下内容的新文档:属性Song_with_composer_key而不是歌曲属性。
这是查询 -
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 INongs RETURN Song来查看歌曲集合发生了怎样的变化。
输出
[ { "_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" } ]
ArangoDB - AQL 示例查询
在本章中,我们将考虑一些针对演员和电影数据库的 AQL 示例查询。这些查询基于图表。
问题
给定演员集合和电影集合,以及用于连接顶点的 actIn 边集合(具有年份属性),如下所示 -
[演员] <- 出演 -> [电影]
我们如何得到 -
- 所有出演“电影1”或“电影2”的演员?
- 所有出演过“电影1”和“电影2”的演员?
- “演员1”和“演员2”之间所有常见的电影?
- 所有出演过 3 部或以上电影的演员?
- 所有电影都有 6 名演员出演?
- 电影的演员人数是多少?
- 演员出演的电影有多少部?
- 演员在 2005 年至 2010 年间出演了多少部电影?
解决方案
在解决并获得上述查询的答案的过程中,我们将使用 Arangosh 创建数据集并对其运行查询。所有 AQL 查询都是字符串,可以简单地复制到您最喜欢的驱动程序而不是 Arangosh。
让我们首先在 Arangosh 中创建一个测试数据集。首先,下载这个文件-
# wget -O dataset.js https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing
输出
... HTTP request sent, awaiting response... 200 OK Length: unspecified [text/html] Saving to: ‘dataset.js’ dataset.js [ <=> ] 115.14K --.-KB/s in 0.01s 2017-09-17 14:19:12 (11.1 MB/s) - ‘dataset.js’ saved [117907]
您可以在上面的输出中看到我们已经下载了一个 JavaScript 文件dataset.js。该文件包含用于在数据库中创建数据集的 Arangosh 命令。我们将使用Arangosh 上的--javascript.execute选项以非交互方式执行多个命令,而不是逐一复制和粘贴命令。将其视为救星命令!
现在在 shell 上执行以下命令 -
$ arangosh --javascript.execute dataset.js
出现提示时提供密码,如上面的屏幕截图所示。现在我们已经保存了数据,因此我们将构建 AQL 查询来回答本章开头提出的具体问题。
第一个问题
让我们回答第一个问题:所有出演过“movie1”或“movie2”的演员。假设,我们想要找到所有出演“TheMatrix”或“TheDevilsAdvocate”的演员的名字 -
我们将从一次一部电影开始,获取演员的名字 -
127.0.0.1:8529@_system> db._query("FOR x IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN x._id").toArray();
输出
我们将收到以下输出 -
[ "actors/Hugo", "actors/Emil", "actors/Carrie", "actors/Keanu", "actors/Laurence" ]
现在我们继续形成两个 NEIGHBORS 查询的 UNION_DISTINCT,这将是解决方案 -
127.0.0.1:8529@_system> db._query("FOR x IN UNION_DISTINCT ((FOR y IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();
输出
[ "actors/Charlize", "actors/Al", "actors/Laurence", "actors/Keanu", "actors/Carrie", "actors/Emil", "actors/Hugo" ]
第二个问题
现在让我们考虑第二个问题:同时出演“movie1”和“movie2”的所有演员。这与上面的问题几乎相同。但这次我们对并集不感兴趣,而是对交集感兴趣 -
127.0.0.1:8529@_system> db._query("FOR x IN INTERSECTION ((FOR y IN ANY 'movies/TheMatrix' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id), (FOR y IN ANY 'movies/TheDevilsAdvocate' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id)) RETURN x").toArray();
输出
我们将收到以下输出 -
[ "actors/Keanu" ]
第三个问题
现在让我们考虑第三个问题:“actor1”和“actor2”之间所有共同的电影。这实际上与 movie1 和 movie2 中关于共同演员的问题相同。我们只需要更改起始顶点即可。举个例子,让我们找到雨果·维文(“Hugo”)和基努·里维斯共同主演的所有电影 -
127.0.0.1:8529@_system> db._query( "FOR x IN INTERSECTION ( ( FOR y IN ANY 'actors/Hugo' actsIn OPTIONS {bfs: true, uniqueVertices: 'global'} RETURN y._id ), ( FOR y IN ANY 'actors/Keanu' actsIn OPTIONS {bfs: true, uniqueVertices:'global'} RETURN y._id ) ) RETURN x").toArray();
输出
我们将收到以下输出 -
[ "movies/TheMatrixReloaded", "movies/TheMatrixRevolutions", "movies/TheMatrix" ]
第四个问题
现在我们来考虑第四个问题。所有出演过 3 部或以上电影的演员。这个问题是不同的;我们不能在这里使用邻居功能。相反,我们将利用 AQL 的边缘索引和 COLLECT 语句进行分组。基本思想是按起始顶点(在该数据集中始终是参与者)对所有边进行分组。然后我们从结果中删除所有电影少于 3 部电影的演员,因为这里我们包含了演员出演的电影数量 -
127.0.0.1:8529@_system> db._query("FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter FILTER counter >= 3 RETURN {actor: actor, movies: counter}"). toArray()
输出
[ { "actor" : "actors/Carrie", "movies" : 3 }, { "actor" : "actors/CubaG", "movies" : 4 }, { "actor" : "actors/Hugo", "movies" : 3 }, { "actor" : "actors/Keanu", "movies" : 4 }, { "actor" : "actors/Laurence", "movies" : 3 }, { "actor" : "actors/MegR", "movies" : 5 }, { "actor" : "actors/TomC", "movies" : 3 }, { "actor" : "actors/TomH", "movies" : 3 } ]
对于剩下的问题,我们将讨论查询的形成,并仅提供查询。读者应该在 Arangosh 终端上自行运行查询。
第五个问题
现在让我们考虑第五个问题:所有由 6 名演员出演的电影。与之前的查询中的想法相同,但使用了相等过滤器。然而,现在我们需要电影而不是演员,所以我们返回_to 属性-
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER counter == 6 RETURN movie").toArray()
电影的演员人数是多少?
我们记得在数据集中,边缘上的_to对应于电影,因此我们计算相同_to出现的频率。这是演员的数量。该查询与之前的查询几乎相同,但在 COLLECT 之后没有 FILTER -
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN {movie: movie, actors: counter}").toArray()
第六个问题
现在让我们考虑第六个问题:演员的电影数量。
我们找到上述查询的解决方案的方式也将帮助您找到此查询的解决方案。
db._query("FOR x IN actsIn COLLECT actor = x._from WITH COUNT INTO counter RETURN {actor: actor, movies: counter}").toArray()
ArangoDB - 如何部署
在本章中,我们将描述部署 ArangoDB 的各种可能性。
部署:单实例
我们已经在前面的一章中学习了如何部署 Linux (Ubuntu) 的单个实例。现在让我们看看如何使用 Docker 进行部署。
部署:Docker
对于使用 docker 进行部署,我们将在我们的计算机上安装 Docker。有关 Docker 的更多信息,请参阅我们的Docker教程。
安装 Docker 后,您可以使用以下命令 -
docker run -e ARANGO_RANDOM_ROOT_PASSWORD = 1 -d --name agdb-foo -d arangodb/arangodb
它将创建并启动 ArangoDB 的 Docker 实例,标识名称为agdbfoo作为 Docker 后台进程。
终端还将打印进程标识符。
默认情况下,端口 8529 保留给 ArangoDB 监听请求。此外,您可能已链接的所有 Docker 应用程序容器都会自动使用此端口。