Arangodb 简明教程
ArangoDB - A Multi-Model First Database
ArangoDB 被其开发者称为原生多模型数据库。这不同于其它 NoSQL 数据库。在此数据库中,数据可以存储为文档、键/值对或图形。并且借助单一的声明式查询语言,可以访问任意或所有数据。此外,可以在单个查询中组合不同的模型。而且,由于其多模型样式,可以制定精益应用程序,这些应用程序将使用任意或全部三种数据模型横向扩展。
Layered vs. Native Multi-Model Databases
在本节中,我们将重点介绍原生多模型数据库与分层多模型数据库之间的关键差异。
许多数据库供应商称自己的产品为“多模型”,但向键/值或文档存储添加图形层并不能算作原生多模型。
借助 ArangoDB,我们可以使用相同查询语言的同一内核,在一个查询中组合不同的数据模型和特性,如我们在上一节中已经指出的那样。在 ArangoDB 中,没有数据模型之间的“切换”,也不存在从 A 到 B 的数据转移来执行查询的情况。与“分层”的方法相比,这为 ArangoDB 带来了性能优势。
The Need for Multimodal Database
解释 [Fowler’s] 的基本思想让我们意识到,使用各种适当的数据模型对持久层(该层是大型软件架构的一部分)的不同部分是有益的。
根据这一点,例如,您可能使用关系数据库来保持结构化表格数据的持久性;使用文档存储来保持非结构化对象数据(如数据);使用键/值存储来保持哈希表的持久性;并且使用图形数据库来保持高度链接的引用数据的持久性。
然而,这种方法的传统实现会导致在同一项目中使用多个数据库。这会导致一些操作摩擦(更复杂的部署、更频繁的升级),以及数据一致性和重复问题。
在统一三个数据模型的数据之后,下一个挑战是设计并实现一种通用查询语言,该语言允许数据管理员表达各种查询,如文档查询、键/值查找、图形查询以及这些查询的任意组合。
graphy queries ,我们的意思是涉及图论考虑因素的查询。特别是,这些可能涉及来自边的特定连接功能。例如, ShortestPath, GraphTraversal 和 Neighbors 。
图形非常适合作为关系的数据模型。在许多现实世界的情况中,例如社交网络、推荐人系统等,一个非常自然的数据模型是图形。它捕捉关系,并且可以在每个边和每个顶点中包含标签信息。此外,JSON 文档非常适合存储此类型的顶点和边数据。
ArangoDB ─ Features
ArangoDB 有许多值得注意的特性。我们将在下面重点介绍突出的特性 −
-
Multi-model Paradigm
-
ACID Properties
-
HTTP API
ArangoDB 支持所有流行的数据库模型。以下是 ArangoDB 支持的几个模型 −
-
Document model
-
Key/Value model
-
Graph model
一个查询语言就足以从数据库中检索数据
四个属性 Atomicity, Consistency, Isolation 和 Durability (ACID) 描述了数据库事务的保证。ArangoDB 支持符合 ACID 的事务。
ArangoDB 允许浏览器等客户端通过 HTTP API 与数据库交互,该 API 以资源为导向并可使用 JavaScript 进行扩展。
ArangoDB - Advantages
以下是使用 ArangoDB 的优点:
Consolidation
作为一种原生多模型数据库,ArangoDB 消除了部署多个数据库的需要,从而减少了组件及其维护的数量。因此,它降低了应用程序的技术栈复杂度。除了满足你的总体技术需求之外,这种简化方式还降低了总体拥有成本并增加了灵活性。
Simplified Performance Scaling
随着应用程序在不断发展,ArangoDB 可使用不同的数据模型来独立地扩展,满足不断增长的性能和存储需求。由于 ArangoDB 可同时横向和纵向扩展,因此当你的性能需求下降(故意、期望变慢)时,可以轻松缩小后端系统的规模,既能节省硬件成本,又能节省运营成本。
Reduced Operational Complexity
多语言持久性的法令是为承担的每一项工作使用最佳工具。某些任务需要文档数据库,而另一些任务则可能需要图形数据库。由于采用单模型数据库,可能会导致多种操作挑战。集成单模型数据库本身就是一项艰巨的任务。但是,最大的挑战是建立一个大型的内聚结构,并在独立的、不相关的数据库系统之间实现数据一致性和容错性。这几乎是不可能的。
多语言持久性可以使用原生多模型数据库来处理,因为它允许轻松拥有多语言数据,但同时又保证了容错系统上的数据一致性。使用 ArangoDB,我们可以针对复杂的工作使用正确的数据模型。
Strong Data Consistency
如果一个人使用多个单模型数据库,数据一致性就会成为一个问题。这些数据库并非设计为相互通信,因此需要实现某种形式的事务功能来使不同模型之间的数据保持一致。
支持 ACID 事务的 ArangoDB 使用单个后端管理不同的数据模型,在单个实例上提供强大的一致性,以及在群集模式下操作时的原子操作。
Fault Tolerance
使用许多不相关的组件来构建容错系统是一项挑战。使用群集时,这项挑战变得更加复杂。部署和维护此类系统需要使用不同技术和/或技术栈的专业知识。此外,集成多个设计为独立运行的子系统会带来巨大的工程和运营成本。
作为一种整合的技术栈,多模型数据库提供了一个优雅的解决方案。ArangoDB 旨在通过不同的数据模型实现现代化模块化架构,也适用于群集使用。
Basic Concepts and Terminologies
在本章中,我们将讨论 ArangoDB 的基本概念和术语。了解与我们正在处理的技术主题相关的基本术语非常重要。
ArangoDB 的术语如下:
-
Document
-
Collection
-
Collection Identifier
-
Collection Name
-
Database
-
Database Name
-
Database Organization
从数据模型的角度来看,ArangoDB 可以被认为是一个面向文档的数据库,因为文档的概念是后者的一个数学理念。面向文档的数据库是 NoSQL 数据库的一个主要类别。
层次关系如下:文档被分组为集合,集合存在于数据库中。
应该很明显,标识符和名称是集合和数据库的两个属性。
通常,存储在文档集合中的两个文档(顶点)通过存储在边集合中的文档(边)链接。这是 ArangoDB 的图表数据模型。它遵循有向标记图的数学概念,只不过边不仅具有标签,而且是成熟的文档。
熟悉了此数据库的核心术语后,我们开始理解 ArangoDB 的图表数据模型。在此模型中,存在两种类型的集合:文档集合和边集合。边集合存储文档,还包含两个特殊属性:第一个是 _from 属性,第二个是 _to 属性。这些属性用于在文档之间创建边(关系),这对图形数据库至关重要。在图形的上下文中,文档集合也称为顶点集合(请参见任何图论书籍)。
现在让我们看看数据库有多么重要。它们很重要,因为数据库内存在集合。对于 ArangoDB 的一个实例,可以有一个或多个数据库。不同的数据库通常用于多租户设置,因为它们内部的不同数据集(集合、文档等)彼此孤立。默认数据库 _system 是特殊的,因为它无法被删除。用户在此数据库中被管理,其凭据对于服务器实例的所有数据库都是有效的。
ArangoDB - System Requirements
在本章中,我们将讨论 ArangoDB 的系统要求。
ArangoDB 的系统要求如下 -
-
装有 Ubuntu 的 VPS 服务器
-
RAM:1GB;CPU:2.2GHz
在本教程中的所有命令中,我们使用了一台 RAM 为 1GB 的 Ubuntu 16.04(xenial)实例,配备一个处理能力为 2.2GHz 的 CPU。并且本教程中的所有 arangosh 命令均针对 ArangoDB 版本 3.1.27 进行测试。
How to Install ArangoDB?
在本节中,我们将了解如何安装 ArangoDB。ArangoDB 已针对许多操作系统和发行版预构建。有关更多详细信息,请参阅 ArangoDB 文档。如前所述,对于本教程,我们将使用 Ubuntu 16.04x64。
第一步是下载其储存库的公钥 -
# wget https://www.arangodb.com/repositories/arangodb31/
xUbuntu_16.04/Release.key
Output
--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
Output
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
Output
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 用户提供密码。小心记录下密码。
在出现以下对话框时选择 yes 选项 -
当你像在上述对话框中那样单击 Yes 时,将出现以下对话框。在此处单击 Yes 。
你还可以使用以下命令检查 ArangoDB 的状态 -
# sudo systemctl status arangodb3
Output
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
Output
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
ArangoDB - Web Interface
在本章中,我们将学习如何启用/禁用身份验证,以及如何将 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
Output
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 这样的已创建用户),而无需在 please specify a password 中输入任何密码。
让我们在关闭身份验证时检查 api 版本 −
# curl --dump - http://127.0.0.1:8529/_api/version
ArangoDB - Example Case Scenarios
在本章中,我们将考虑两种示例场景。这些示例更容易理解,将帮助我们了解 ArangoDB 功能的工作方式。
为了演示 API,ArangoDB 预先加载了一组易于理解的图。在你的 ArangoDB 中创建这些图的实例有两种方法 −
-
在 Web 界面的创建图窗口中添加“示例”选项卡,
-
或在 Arangosh 中加载模块 @arangodb/graph-examples/example-graph 。
首先,让我们借助 Web 界面加载一个图。为此,启动 Web 界面并单击 graphs 选项卡。
显示 Create Graph 对话框。向导包含两个选项卡 – Examples 和 Graph 。 Graph 选项卡默认打开;假设我们要创建一个新图,它会询问图的名称和其他定义。
现在,我们将上传已创建的图形。为此,我们将选择 Examples 选项卡。
我们可以看到三个示例图形。选择 Knows_Graph 并单击绿色按钮创建。
创建好后,可以在用于创建以下图片的 Web 界面中检查它们。
The Knows_Graph
现在让我们看看 Knows_Graph 如何工作。选择 Knows_Graph,它将获取图形数据。
Knows_Graph 由一个通过一个边集合 knows 连接的顶点集合 persons 组成。它将包含五个人 Alice、Bob、Charlie、Dave 和 Eve 作为顶点。我们将拥有以下定向关系
Alice knows Bob
Bob knows Charlie
Bob knows Dave
Eve knows Alice
Eve knows Bob
如果你单击一个节点(顶点),比如“bob”,它将显示 ID(人物/bob)属性名称。
如果单击任何边,它将显示 ID(knows/4590)属性。
这就是创建它的方式,即检查其顶点和边。
让我们再添加一个图形,这次使用 Arangosh。为此,我们需要在 ArangoDB 配置文件中包含另一个端点。
How to Add Multiple Endpoints
打开配置文件 -
# 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>
ArangoDB - Data Models and Modeling
在本章中,我们将重点关注以下主题 -
-
Database Interaction
-
Data Model
-
Data Retrieval
ArangoDB 支持基于文档的数据模型和基于图的数据模型。让我们首先描述基于文档的数据模型。
ArangoDB 的文档与 JSON 格式非常相似。一个文档中包含零个或多个属性,每个属性都附加一个值。值可以是原子类型,例如数字、布尔值或空,文字字符串或复合数据类型,例如嵌入式文档/对象或数组。数组或子对象可能由这些数据类型组成,这意味着单个文档可以表示非平凡的数据结构。
在层次结构中,文档被组织成集合,这些集合可能不包含文档(理论上)或包含多个文档。人们可以将文档与行进行比较,将集合与表进行比较(此处表和行指关系数据库管理系统 - RDBMS 的那些)。
但在 RDBMS 中,定义列是将记录存储到表中的先决条件,称这些定义为模式。然而,作为新特性,ArangoDB 是无模式的——在先验中没有任何理由指定文档会具有的属性。
而且,与 RDBMS 不同的是,每个文档都可以采用与其他文档完全不同的方式来构建。这些文档可以保存在一个集合中。实际上,集合中的文档之间可能存在一些共同特征,但是数据库系统(即 ArangoDB 本身)不会把你绑定到特定的数据结构上。
现在,我们将尝试理解 ArangoDB 的 [ graph data model ],它需要两种集合——第一种是文档集合(在群论语言中称为顶点集合),第二种是边缘集合。这两类之间有一个微妙的区别。边缘集合也会存储文档,但它们的特征是包含两个唯一属性 _from 和 _to ,用于在文档之间创建关系。实际上,一个文档(边)会链接两个文档(顶点),这两个文档都分别存储在各自的集合中。此架构源于标签有向图的图论概念,它排除了不仅可以有标签,而且也可以是完整 JSON(像文档一样)的边缘。
为了计算新的数据、删除文档或对文档进行控制,会用到查询,它依给定条件选择或过滤文档。查询可以像“示例查询”那么简单,也可以像“联接”那么复杂。查询都用 AQL(ArangoDB 查询语言)编写。
ArangoDB - Database Methods
在本章中,我们将讨论 ArangoDB 中不同的数据库方法。
首先,让我们获取数据库的属性——
-
Name
-
ID
-
Path
首先,我们调用 Arangosh。一旦调用 Arangosh,我们将列出我们到目前为止创建的数据库——
我们将使用以下代码行调用 Arangosh——
127.0.0.1:8529@_system> db._databases()
Output
[
"_system",
"song_collection"
]
我们看到两个数据库,一个 [ _system ] 是默认创建的,另一个 [ song_collection ] 是我们创建的。
现在,让我们使用以下代码行切换到 song_collection 数据库——
127.0.0.1:8529@_system> db._useDatabase("song_collection")
Output
/var/lib/arangodb3/databases/database-4838
现在,让我们使用以下代码行检查是否在系统数据库中——
127.0.0.1:8529@song_collection&t; db._isSystem()
ArangoDB - Crud Operations
在本章中,我们将学习使用 Arangosh 执行的不同操作。
以下是可使用 Arangosh 的可能操作:
-
Creating a Document Collection
-
Creating Documents
-
Reading Documents
-
Updating Documents
让我们从创建一个新数据库开始。我们将使用以下代码行创建一个新数据库:
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')
Output
[ArangoCollection 4890, "songs" (type document, status loaded)]
127.0.0.1:8529@song_collection>
让我们向“songs”集合中添加一些文档(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"})
Output
{
"_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---"
}
How to Read Documents
可以使用 _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
}
How to Update Documents
可以使用 replace 和 update 更新保存的数据。
update 函数修复一个文档,并将其与给定的属性合并。另一方面,replace 函数将用一个新文档替换以前的文档。即使提供了完全不同的属性,替换仍将发生。我们首先将观察非破坏性更新,更新歌曲中的 Production` 属性:
127.0.0.1:8529@song_collection> db.songs.update("songs/A_Man",{production:
"Top Banana"});
Output
{
"_id" : "songs/A_Man",
"_key" : "A_Man",
"_rev" : "_VjVOcqe---",
"_oldRev" : "_VjVClbW---"
}
现在,让我们读取更新的歌曲的属性:
127.0.0.1:8529@song_collection> db.songs.document('A_Man');
Output
{
"_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"
}
可以使用 update 函数轻松更新大文档,尤其是在属性很少的情况下。
相反, replace 函数将在将其用于同一文档时废除您的数据。
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');
How to Remove Documents
remove 函数与文档句柄结合使用,可从集合中删除文档:
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
Crud Operations using Web Interface
在上一个章节中,我们学习了如何使用命令行 Arangosh 对文档执行各种操作。我们现在将学习如何使用网络界面执行同样的操作。首先,在浏览器的地址栏中输入以下地址 - [role="bare"] [role="bare"]http://your_server_ip:8529/_db/song_collection/_admin/aardvark/index.html#login 您将被定向到以下登录页面。
现在,输入用户名和密码。
如果成功,将出现以下屏幕。我们需要为要处理的数据库做出选择,其中 _system 数据库是默认数据库。让我们选择 song_collection 数据库,然后单击绿色选项卡 −
Creating a Collection
在本节中,我们将学习如何创建集合。按顶部导航栏中的集合选项卡。
我们命令行添加的 songs 集合可见。单击它将显示条目。我们现在将使用网络界面添加一个 artists’ 集合。我们在 Arangosh 中创建的 songs 集合已经在那里了。在名称字段中,在出现的 New Collection 对话框中编写 artists 。可以安全地忽略高级选项,默认集合类型(即 Document)也是可以的。
单击“保存”按钮将最终创建该集合,现在此页面上将同时显示两个集合。
Filling Up the Newly Created Collection with Documents
单击 artists 集合时,系统将会显示一个空集合 −
要添加文档,您需要单击放置在右上角的 + 号。当系统提示您输入一个 _key 时,输入 Affable_Balding 作为键。
现在,一个表单将用于添加和编辑文档的属性。有两种方式可以添加属性: Graphical 和 Tree 。图形方式直观但很慢,因此,我们将切换到 Code 视图,并使用树形下拉菜单来选择它 −
为简化过程,我们已经用 JSON 格式生成了样本数据,您可以将其复制并粘贴到查询编辑器区域 −
{"artist": "Johnny Mercer", "title":"Affable Balding Me", "composer": "Robert Emmett Dolan", "Year": 1950}
(注:只应该使用一对大括号;请参见下面的截图)
您也许会注意到,我们在代码视图模式下对键和值都加了引号。现在,单击 Save 。在成功完成后,页面上会短暂出现一个绿色的闪光。
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"
}
]
ArangoDB - AQL Example Queries
在本章中,我们将思考一个 @ {s0} 数据库上的几个 AQL 示例查询。这些查询都基于图表。
Problem
给定一组演员和一组电影,以及一个 actIn 边缘集合(带有一个 year 属性)以按照如下所示的方式连接顶点 −
@ {s1}
我们如何获得 −
-
在“movie1”或“movie2”中演出的所有演员?
-
在“movie1”和“movie2”中都演出的所有演员?
-
“actor1”和“actor2”之间的所有公共电影?
-
在 3 部或更多电影中演出的所有演员?
-
正好 6 位演员出演的所有电影?
-
根据电影的演员数量?
-
根据演员的电影数量?
-
在 2005 年到 2010 年之间演员出演的电影数量?
Solution
在解决上述查询并获取答案的过程中,我们将使用 Arangosh 创建数据集并在其上运行查询。所有 AQL 查询都是字符串,可以轻松复制到您的首选驱动程序中,而不是 Arangosh。
我们首先在 Arangosh 中创建一个测试数据集。首先,下载 @ {s2} −
# wget -O dataset.js
https://drive.google.com/file/d/0B4WLtBDZu_QWMWZYZ3pYMEdqajA/view?usp=sharing
Output
...
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 文件 @ {s3}。该文件包含用于在数据库中创建数据集的 Arangosh 命令。我们不会逐个复制和粘贴这些命令,而是使用 Arangosh 上的 @ {s4} 选项来非交互式地执行多个命令。这简直是救命命令!
现在在 shell 上执行以下命令 −
$ arangosh --javascript.execute dataset.js
当提示时提供密码,如您在上述屏幕截图中看到的。现在我们已经保存了数据,因此我们将构建 AQL 查询来回答本章开头提出的具体问题。
First Question
我们来看第一个问题:@ {s5}。假设,我们想要找到在“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();
Output
我们将接收以下输出 −
[
"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();
Output
[
"actors/Charlize",
"actors/Al",
"actors/Laurence",
"actors/Keanu",
"actors/Carrie",
"actors/Emil",
"actors/Hugo"
]
Second Question
现在,我们考虑第二个问题: All actors who acted in both "movie1" AND "movie2" 。这几乎与上述问题完全相同。但这次,我们不感兴趣于 UNION,而感兴趣于 INTERSECTION −
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();
Third Question
现在,我们考虑第三个问题: All common movies between "actor1" and "actor2" 。这实际上与电影 1 和电影 2 中的共同演员问题完全相同。我们只需要更改起始顶点即可。例如,让我们找出让休·杰克曼(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();
Output
我们将接收以下输出 −
[
"movies/TheMatrixReloaded",
"movies/TheMatrixRevolutions",
"movies/TheMatrix"
]
Fourth Question
现在,我们考虑第四个问题。 All actors who acted in 3 or more movies 。这个问题有所不同;我们不能在此处使用邻居函数。相反,我们将利用 AQL 的边缘索引和 COLLECT 语句进行分组。基本思想是按 startVertex (在该数据集始终为演员)对所有边缘进行分组。然后,我们从结果中删除电影数量少于 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()
Output
[
{
"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 终端上自行运行查询。
Fifth Question
现在,我们考虑第五个问题: All movies where exactly 6 actors acted in 。思路与之前的查询相同,但使用等式筛选器。然而,现在我们需要电影而不是演员,所以我们返回 _to attribute −
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter FILTER
counter == 6 RETURN movie").toArray()
根据电影的演员数量?
我们记得在我们的数据集 _to 中,边缘对应于电影,所以我们统计 _to 出现的次数。这是演员数量。该查询几乎与之前的查询相同,但 without the FILTER after COLLECT −
db._query("FOR x IN actsIn COLLECT movie = x._to WITH COUNT INTO counter RETURN
{movie: movie, actors: counter}").toArray()
ArangoDB - How to Deploy
在本章中,我们将描述部署 ArangoDB 的各种可能性。
Deployment: Docker
若要使用 docker 进行部署,我们将在我们的机器上安装 Docker。有关 Docker 的更多信息,请参阅我们在 Docker 中的教程。
安装 Docker 后,你可以使用以下命令 -
docker run -e ARANGO_RANDOM_ROOT_PASSWORD = 1 -d --name agdb-foo -d
arangodb/arangodb
它将创建并启动 Docker 实例,并将其标识名称 agdbfoo 作为 Docker 后台进程。
终端还会打印进程标识符。
默认情况下,8529 端口是 ArangoDB 监听请求的保留端口。此外,此端口还可以自动用于您可能已链接的所有 Docker 应用程序容器。