本文通过以下文章概述而来
https://www.arangodb.com/docs/stable/aql/tutorial.html
一.ArangoDB和传统数据库的区别
二.AQL数据结构
每个文档都需要一个唯一的_key,该_key在集合中标识它。_id是一个计算的属性,是集合名称的串联,一个collection name/和key。它唯一标识数据库中的文档。_rev是由系统管理的修订ID。
{
"_key": "2861650",
"_id": "Characters/2861650",
"_rev": "_V1bzsXa---",
"name": "Ned",
"surname": "Stark",
"alive": true,
"age": 41,
"traits": ["A","H","C","N","P"]
},
三.crud操作
1. 查询
我们可以在AQL函数DOCUMENT()的帮助下使用文档密钥或文档ID检索特定文档
如:
RETURN DOCUMENT("Characters", "2861650")
// --- or ---
RETURN DOCUMENT("Characters/2861650")
2. 增加操作
INSERT document INTO collectionName
示例:
INSERT {
"name": "Ned",
"surname": "Stark",
"alive": true,
"age": 41,
"traits": ["A","H","C","N","P"]
} INTO Characters
- 用let定义批量数据
LET variableName = valueExpression
数据存放方式[ {…}, {…}, … ]
LET data = [
{ "name": "Robert", "surname": "Baratheon", "alive": false, "traits": ["A","H","C"] },
{ "name": "Jaime", "surname": "Lannister", "alive": true, "age": 36, "traits": ["A","F","B"] },
{ "name": "Catelyn", "surname": "Stark", "alive": false, "age": 40, "traits": ["D","H","C"] },
{ "name": "Cersei", "surname": "Lannister", "alive": true, "age": 36, "traits": ["H","E","F"] },
{ "name": "Daenerys", "surname": "Targaryen", "alive": true, "age": 16, "traits": ["D","H","C"] },
{ "name": "Jorah", "surname": "Mormont", "alive": false, "traits": ["A","B","C","F"] },
{ "name": "Petyr", "surname": "Baelish", "alive": false, "traits": ["E","G","F"] },
{ "name": "Viserys", "surname": "Targaryen", "alive": false, "traits": ["O","L","N"] },
{ "name": "Jon", "surname": "Snow", "alive": true, "age": 16, "traits": ["A","B","C","F"] },
{ "name": "Sansa", "surname": "Stark", "alive": true, "age": 13, "traits": ["D","I","J"] },
{ "name": "Arya", "surname": "Stark", "alive": true, "age": 11, "traits": ["C","K","L"] },
{ "name": "Robb", "surname": "Stark", "alive": false, "traits": ["A","B","C","K"] },
{ "name": "Theon", "surname": "Greyjoy", "alive": true, "age": 16, "traits": ["E","R","K"] },
{ "name": "Bran", "surname": "Stark", "alive": true, "age": 10, "traits": ["L","J"] },
{ "name": "Joffrey", "surname": "Baratheon", "alive": false, "age": 19, "traits": ["I","L","O"] },
{ "name": "Sandor", "surname": "Clegane", "alive": true, "traits": ["A","P","K","F"] },
{ "name": "Tyrion", "surname": "Lannister", "alive": true, "age": 32, "traits": ["F","K","M","N"] },
{ "name": "Khal", "surname": "Drogo", "alive": false, "traits": ["A","C","O","P"] },
{ "name": "Tywin", "surname": "Lannister", "alive": false, "traits": ["O","M","H","F"] },
{ "name": "Davos", "surname": "Seaworth", "alive": true, "age": 49, "traits": ["C","K","P","F"] },
{ "name": "Samwell", "surname": "Tarly", "alive": true, "age": 17, "traits": ["C","L","I"] },
{ "name": "Stannis", "surname": "Baratheon", "alive": false, "traits": ["H","O","P","M"] },
{ "name": "Melisandre", "alive": true, "traits": ["G","E","H"] },
{ "name": "Margaery", "surname": "Tyrell", "alive": false, "traits": ["M","D","B"] },
{ "name": "Jeor", "surname": "Mormont", "alive": false, "traits": ["C","H","M","P"] },
{ "name": "Bronn", "alive": true, "traits": ["K","E","C"] },
{ "name": "Varys", "alive": true, "traits": ["M","F","N","E"] },
{ "name": "Shae", "alive": false, "traits": ["M","D","G"] },
{ "name": "Talisa", "surname": "Maegyr", "alive": false, "traits": ["D","C","B"] },
{ "name": "Gendry", "alive": false, "traits": ["K","C","A"] },
{ "name": "Ygritte", "alive": false, "traits": ["A","P","K"] },
{ "name": "Tormund", "surname": "Giantsbane", "alive": true, "traits": ["C","P","A","I"] },
{ "name": "Gilly", "alive": true, "traits": ["L","J"] },
{ "name": "Brienne", "surname": "Tarth", "alive": true, "age": 32, "traits": ["P","C","A","K"] },
{ "name": "Ramsay", "surname": "Bolton", "alive": true, "traits": ["E","O","G","A"] },
{ "name": "Ellaria", "surname": "Sand", "alive": true, "traits": ["P","O","A","E"] },
{ "name": "Daario", "surname": "Naharis", "alive": true, "traits": ["K","P","A"] },
{ "name": "Missandei", "alive": true, "traits": ["D","L","C","M"] },
{ "name": "Tommen", "surname": "Baratheon", "alive": true, "traits": ["I","L","B"] },
{ "name": "Jaqen", "surname": "H'ghar", "alive": true, "traits": ["H","F","K"] },
{ "name": "Roose", "surname": "Bolton", "alive": true, "traits": ["H","E","F","A"] },
{ "name": "The High Sparrow", "alive": true, "traits": ["H","M","F","O"] }
]
FOR d IN data
INSERT d INTO Characters
- 循环遍历语法
FOR variableName IN collectionName
例:遍历character中的数据
FOR c IN Characters
RETURN c
3.更新操作
UPDATE documentKey WITH object IN collectionName
例
UPDATE "2861650" WITH { alive: false } IN Characters
也可使用循环操作
FOR c IN Characters
UPDATE c WITH { season: 1 } IN Characters
如需更新所有内容可使用replace操作
REPLACE "2861650" WITH {
name: "Ned",
surname: "Stark",
alive: false,
age: 41,
traits: ["A","H","C","N","P"]
} IN Characters
4. 删除操作
REMOVE documentKey IN collectionName
- 返回数据
FOR c IN Characters
RETURN c
- 等于匹配
FOR c IN Characters
FILTER c.name == "Ned"
RETURN c
四.匹配查询
- 单个匹配
FOR c IN Characters
FILTER c.age >= 13
RETURN c.name
- 多个匹配
FOR c IN Characters
FILTER c.age < 13 AND c.age != null
RETURN { name: c.name, age: c.age }
- 替代匹配
FOR c IN Characters
FILTER c.name == "Jon" OR c.name == "Joffrey"
RETURN { name: c.name, surname: c.surname }
五. 排序和限制查询
- 限制查询
返回5个数据
FOR c IN Characters
LIMIT 5
RETURN c.name
跳过一定数量的记录并返回接下来的n个数据
FOR c IN Characters
LIMIT 2, 5
RETURN c.name
- 排序
例:对名称进行排序
FOR c IN Characters
SORT c.name
LIMIT 10
RETURN c.name
在被排序参数后加desc
即可降序排列
当然也可以进行多参数排序
例:对surname升序,对name降序
FOR c IN Characters
FILTER c.surname
SORT c.surname, c.name DESC
LIMIT 10
RETURN {
surname: c.surname,
name: c.name
}
六. 联合查询
对于如下示例,我们的traits数组中的每一个字母对应一个trait
{
"name": "Ned",
"surname": "Stark",
"alive": false,
"age": 41,
"traits": ["A","H","C","N","P"]
}
将具体traits插入
let data = [
{ "_key": "A", "en": "strong", "de": "stark" },
{ "_key": "B", "en": "polite", "de": "freundlich" },
{ "_key": "C", "en": "loyal", "de": "loyal" },
{ "_key": "D", "en": "beautiful", "de": "schön" },
{ "_key": "E", "en": "sneaky", "de": "hinterlistig" },
{ "_key": "F", "en": "experienced", "de": "erfahren" },
{ "_key": "G", "en": "corrupt", "de": "korrupt" },
{ "_key": "H", "en": "powerful", "de": "einflussreich" },
{ "_key": "I", "en": "naive", "de": "naiv" },
{ "_key": "J", "en": "unmarried", "de": "unverheiratet" },
{ "_key": "K", "en": "skillful", "de": "geschickt" },
{ "_key": "L", "en": "young", "de": "jung" },
{ "_key": "M", "en": "smart", "de": "klug" },
{ "_key": "N", "en": "rational", "de": "rational" },
{ "_key": "O", "en": "ruthless", "de": "skrupellos" },
{ "_key": "P", "en": "brave", "de": "mutig" },
{ "_key": "Q", "en": "mighty", "de": "mächtig" },
{ "_key": "R", "en": "weak", "de": "schwach" }
]
FOR d IN data
INSERT d INTO Traits
如需将一下数据合并到上文中
FOR c IN Characters
RETURN DOCUMENT("Traits", c.traits)[*].en
[
[
"strong",
"powerful",
"loyal",
"rational",
"brave"
],
[
"beautiful",
"powerful",
"loyal"
],
...
]
可以使用如下merge
方法
FOR c IN Characters
RETURN MERGE(c, { traits: DOCUMENT("Traits", c.traits)[*].en } )
[
{
"_id": "Characters/2861650",
"_key": "2861650",
"_rev": "_V1bzsXa---",
"age": 41,
"alive": false,
"name": "Ned",
"surname": "Stark",
"traits": [
"strong",
"powerful",
"loyal",
"rational",
"brave"
]
},
{
"_id": "Characters/2861653",
"_key": "2861653",
"_rev": "_V1bzsXa--B",
"age": 40,
"alive": false,
"name": "Catelyn",
"surname": "Stark",
"traits": [
"beautiful",
"powerful",
"loyal"
]
},
...
]
MERGE()
函数将对象合并在一起。由于我们使用了与原始字符属性具有相同属性名称traits
的对象{ traits: ... }
,后者被合并操作覆盖。
注:
DOCUMENT()
函数使用主索引
快速查找文档
。然而,它仅限于通过其标识符
查找
文件
- 便捷方法
FOR c IN Characters
RETURN MERGE(c, {
traits: (
FOR key IN c.traits
FOR t IN Traits
FILTER t._key == key
RETURN t.en
)
})
七. 对节点的边生成以及遍历
父和子之间的关系可以建模为图表。在ArangoDB中,两个文档(父Document和子Document)可以通过边缘Document链接。用Edge Document存储边集合,并有两个额外的属性:_from和_to。他们通过Document ID(_id)引用任何两个Document
构建边关系示例
LET data = [
{
"parent": { "name": "Ned", "surname": "Stark" },
"child": { "name": "Robb", "surname": "Stark" }
}, {
"parent": { "name": "Ned", "surname": "Stark" },
"child": { "name": "Sansa", "surname": "Stark" }
}, {
"parent": { "name": "Ned", "surname": "Stark" },
"child": { "name": "Arya", "surname": "Stark" }
}, {
"parent": { "name": "Ned", "surname": "Stark" },
"child": { "name": "Bran", "surname": "Stark" }
}, {
"parent": { "name": "Catelyn", "surname": "Stark" },
"child": { "name": "Robb", "surname": "Stark" }
}, {
"parent": { "name": "Catelyn", "surname": "Stark" },
"child": { "name": "Sansa", "surname": "Stark" }
}, {
"parent": { "name": "Catelyn", "surname": "Stark" },
"child": { "name": "Arya", "surname": "Stark" }
}, {
"parent": { "name": "Catelyn", "surname": "Stark" },
"child": { "name": "Bran", "surname": "Stark" }
}, {
"parent": { "name": "Ned", "surname": "Stark" },
"child": { "name": "Jon", "surname": "Snow" }
}, {
"parent": { "name": "Tywin", "surname": "Lannister" },
"child": { "name": "Jaime", "surname": "Lannister" }
}, {
"parent": { "name": "Tywin", "surname": "Lannister" },
"child": { "name": "Cersei", "surname": "Lannister" }
}, {
"parent": { "name": "Tywin", "surname": "Lannister" },
"child": { "name": "Tyrion", "surname": "Lannister" }
}, {
"parent": { "name": "Cersei", "surname": "Lannister" },
"child": { "name": "Joffrey", "surname": "Baratheon" }
}, {
"parent": { "name": "Jaime", "surname": "Lannister" },
"child": { "name": "Joffrey", "surname": "Baratheon" }
}
]
FOR rel in data
LET parentId = FIRST(
FOR c IN Characters
FILTER c.name == rel.parent.name
FILTER c.surname == rel.parent.surname
LIMIT 1
RETURN c._id
)
LET childId = FIRST(
FOR c IN Characters
FILTER c.name == rel.child.name
FILTER c.surname == rel.child.surname
LIMIT 1
RETURN c._id
)
FILTER parentId != null AND childId != null
INSERT { _from: childId, _to: parentId } INTO ChildOf
RETURN NEW
如果知道需要连接节点的id亦可以用如下语句操作
INSERT { _from: "Characters/robb", _to: "Characters/ned" } INTO ChildOf
接下来我们能够通过以下图示来了解节点之间的查询关系
示例:
1..1
代表最小
和最大
遍历深度为1
OUTBOUND
代表查询父节点
其后接的c代表从此节点开始寻找
FOR c IN Characters
FILTER c.name == "Bran"
FOR v IN 1..1 OUTBOUND c ChildOf
RETURN v.name
[
"Ned",
"Catelyn"
]
我们也可以从父母向反向边缘方向寻找其子节点(即INBOUND)
FOR c IN Characters
FILTER c.name == "Ned"
FOR v IN 1..1 INBOUND c ChildOf
RETURN v.name
[
"Robb",
"Sansa",
"Jon",
"Arya",
"Bran"
]
当然,也可以查找孙子节点
FOR c IN Characters
FILTER c.name == "Tywin"
FOR v IN 2..2 INBOUND c ChildOf
RETURN v.name
[
"Joffrey",
"Joffrey"
]
- 可变深度的遍历
FOR c IN Characters
FILTER c.name == "Joffrey"
FOR v IN 1..2 OUTBOUND c ChildOf
RETURN DISTINCT v.name
[
"Cersei",
"Tywin",
"Jaime"
]