Персональный блог-Добро пожаловать в гости
Язык запросов ArangoDB (AQL) похож на язык структурированных запросов (SQL) по своему назначению. Оба поддерживают чтение и изменение данных коллекции, но AQL не поддерживает операции определения данных, такие как создание и удаление баз данных, коллекций и индексов.
Хотя некоторые ключевые слова перекрываются, синтаксис AQL отличается от SQL. Например, предложения SQL WHERE и AQL FILTER эквивалентны, поскольку они оба определяют условия, при которых возвращаются результаты. Однако SQL использует предопределенную последовательность, чтобы определить, где должен появиться оператор WHERE. В AQL предложения выполняются слева направо, поэтому позиция предложения в запросе FILTER определяет его приоритет.
Несмотря на эти различия, у любого, кто имеет опыт работы с SQL, не должно возникнуть трудностей с изучением AQL.
1. Предварительный просмотр данных
На этот раз используется 43 фрагмента данных, и каждый фрагмент данных содержит шесть полей, таких как фамилия, возраст, статус активности и характеристики.
Каждая из этих функций имеет случайную букву в качестве ключа документа. Метки признаков доступны на английском и немецком языках.
Место состоит из названия места, широты и долготы:
2. Базовый CRUD
Создать коллекцию:
Перед созданием документа необходимо создать коллекцию, в которую его поместить.Коллекции можно создавать через веб-интерфейс, арангош или драйвер. AQL не может создавать коллекции.
Щелкните КОЛЛЕКЦИИ в веб-интерфейсе, затем щелкните Добавить коллекцию и введите Имя персонажа. Подтвердить с сохранением. Новая коллекция появится в списке.
Вставьте один объект:
Вставить документ с помощью AQL
INSERT {
"name": "Ned",
"surname": "Stark",
"alive": true,
"age": 41,
"traits": ["A","H","C","N","P"]
} INTO Characters
грамматика:
INSERT document INTO collectionName
Документ представляет собой объект, состоящий из пар ключ-значение свойства. Кавычки для ключей атрибутов необязательны в AQL. Ключи всегда являются строками, а значения свойств могут иметь разные типы:
- null
- boolean (true, false)
- number (integer and floating point)
- string
- array
- object
Массовая вставка объектов:
AQL не допускает нескольких операций INSERT для одной и той же коллекции в одном запросе. Однако можно вставить несколько документов, используя тело цикла FOR.
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
грамматика:
LET variableName = valueExpression
Ключевое слово LET определяет массив переменных данных и значений объекта с тем же именем в формате[ {...}, {...}, ... ]
FOR variableName IN expression
Используется для перебора каждого элемента массива данных. В каждом цикле назначьте элемент переменной d. Затем используйте эту переменную в операторе INSERT. Эквивалент следующего формата:
INSERT {
"name": "Robert",
"surname": "Baratheon",
"alive": false,
"traits": ["A","H","C"]
} INTO Characters
INSERT {
"name": "Jaime",
"surname": "Lannister",
"alive": true,
"age": 36,
"traits": ["A","F","B"]
} INTO Characters
...
забрать
Получить все документы в коллекции:
FOR c IN Characters
RETURN c
грамматика:
FOR variableName IN collectionName
Для каждого документа в коллекции поочередно присваивайте значение переменной c, а затем возвращайте этот документ в соответствии с телом цикла.
Выберите один из документов следующим образом:
{
"_key": "2861650",
"_id": "Characters/2861650",
"_rev": "_V1bzsXa---",
"name": "Ned",
"surname": "Stark",
"alive": true,
"age": 41,
"traits": ["A","H","C","N","P"]
},
Документ содержит четыре свойства, которые мы сохраняем, а также еще три свойства, добавленные системой базы данных:
-
_key: ключ документа, пользователь может указать ключ документа при создании документа, или он может автоматически присвоить уникальное значение, не может быть изменен, только для чтения
-
_id: имя коллекции/ключ документа, только для чтения
-
_rev: Идентификатор версии, управляемой системой, только для чтения.
Чтобы получить конкретный документ:
RETURN DOCUMENT("Characters", "2861650")
// --- or ---
RETURN DOCUMENT("Characters/2861650")
возвращение:
[
{
"_key": "2861650",
"_id": "Characters/2861650",
"_rev": "_V1bzsXa---",
"name": "Ned",
"surname": "Stark",
"alive": true,
"age": 41,
"traits": ["A","H","C","N","P"]
}
]
грамматика:
DOCUMENT()
Получить определенный документ, используя _key или _id, функция также позволяет получить несколько документов одновременно
RETURN DOCUMENT("Characters", ["2861650", "2861653"])
// --- or ---
RETURN DOCUMENT(["Characters/2861650", "Characters/2861653"])
Обновить документацию:
Изменить существующие файлы:
UPDATE "2861650" WITH { alive: false } IN Characters
语法:
UPDATE documentKey WITH object IN collectionName
Обновляет указанные документы с перечисленными свойствами (добавляя их, если они не существуют), но оставляет остальные без изменений. Чтобы заменить все содержимое документа, используйте функцию REPLACE:
REPLACE "2861650" WITH {
name: "Ned",
surname: "Stark",
alive: false,
age: 41,
traits: ["A","H","C","N","P"]
} IN Characters
Функция также работает для циклов, таких как добавление новых свойств ко всем документам:
FOR c IN Characters
UPDATE c WITH { season: 1 } IN Characters
Удалить файлы:
грамматика:
REMOVE _key IN Collectiosname
Чтобы полностью удалить документ из коллекции, требуется операция REMOVE. Он работает так же, как и другие операции модификации, но без предложения WITH:
REMOVE "2861650" IN Characters
3. Сопоставление файлов
грамматика:
FILTER
Найдите документы, которые удовлетворяют более сложным условиям, чем равенство _key, имея возможность формулировать произвольные условия для соответствия документов.
Равное условие:
FOR c IN Characters
FILTER c.name == "Ned"
RETURN c
Условие фильтрации следующее: «Имя атрибута символьного документа должно быть равно строке Ned». Возвращает символьный документ, если применяется условие.
Состояние области:
FOR c IN Characters
FILTER c.age >= 13
RETURN c.name
Различные условия:
FOR c IN Characters
FILTER c.age < 13
FILTER c.age != null
RETURN { name: c.name, age: c.age }
//or
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 }
В-четвертых, сортировка и ограничения
Синтаксис ограничения:
LIMIT()
За LIMIT следует максимальное отображаемое число, которое ограничивает количество строк, отображаемых в результате.
FOR c IN Characters
LIMIT 5
RETURN c.name
Вы также можете использовать LIMIT, чтобы пропустить определенное количество записей и вернуться к следующим n документам:
FOR c IN Characters
LIMIT 2, 5
RETURN c.name
Синтаксис сортировки:
SORT()
DESC по убыванию, чтобы изменить порядок сортировки
FOR c IN Characters
SORT c.name DESC
LIMIT 10
RETURN c.name
Сортировать по нескольким полям
FOR c IN Characters
FILTER c.surname
SORT c.surname, c.name
LIMIT 10
RETURN {
surname: c.surname,
name: c.name
}
Роль ФИЛЬТРА здесь состоит в том, чтобы вести записи только с непустой фамилией.
5. Комбинация
грамматика:MERGE()
Функция MERGE() заключается в объединении объектов вместе. Последние переопределяются при слиянии, потому что используются исходные свойства персонажа { черты: ... }.
FOR c IN Characters
RETURN MERGE(c, { traits: DOCUMENT("Traits", c.traits)[*].en } )
6. Схема работы
Создайте график:
грамматика:
INSERT { _from: _id(A), _to: _id(B) } INTO ChildOf
Пример: Сначала создайте новую коллекцию и обязательно измените тип коллекции на Edge.
Затем, запрашивая данные из нескольких коллекций, результаты сохраняются в пограничной коллекции.
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( //FIRST()提取第一个元素
FOR c IN Characters
FILTER c.name == rel.parent.name //筛选条件
FILTER c.surname == rel.parent.surname
LIMIT 1
RETURN c._id //返回_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 //剔除_id都为空的记录
INSERT { _from: childId, _to: parentId } INTO ChildOf //将数据插入边集合
RETURN NEW //返回数据
Вы также можете создавать граничные данные напрямую:
INSERT { _from: "Characters/robb", _to: "Characters/ned" } INTO ChildOf
Пройдите по графику:
грамматика:
FOR v IN 1..1 OUTBOUND _id ChildOf
RETURN v.name
其中1..1为遍历深度
Пример:
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 == "Tywin"
FOR v IN 2..2 INBOUND c ChildOf
RETURN DISTINCT v.name
输出:
[
"Joffrey"
]
Обход следующий:
Следует отметить, что «1..1» ограничивает глубину обхода до 1, «2..2» ограничивает глубину обхода до 2, а «1..2» ограничивает глубину обхода до 1 или 2.
7. Геопространственный запрос
данные о местоположении
Создайте коллекцию местоположений:
Введите данные о местоположении:
LET places = [
{ "name": "Dragonstone", "coordinate": [ 55.167801, -6.815096 ] },
{ "name": "King's Landing", "coordinate": [ 42.639752, 18.110189 ] },
{ "name": "The Red Keep", "coordinate": [ 35.896447, 14.446442 ] },
{ "name": "Yunkai", "coordinate": [ 31.046642, -7.129532 ] },
{ "name": "Astapor", "coordinate": [ 31.50974, -9.774249 ] },
{ "name": "Winterfell", "coordinate": [ 54.368321, -5.581312 ] },
{ "name": "Vaes Dothrak", "coordinate": [ 54.16776, -6.096125 ] },
{ "name": "Beyond the wall", "coordinate": [ 64.265473, -21.094093 ] }
]
FOR place IN places
INSERT place INTO Locations
Настройте геопространственный индекс:
В интерфейсе COLLECTIONS добавьте новый Indexes и установите его в качестве поля координат:
Найти близлежащие места
грамматика:
NEAR()
Найти ближайшую точку отсчета координат
FOR loc IN NEAR(Locations, 53.35, -6.26, 3)
RETURN {
name: loc.name,
latitude: loc.coordinate[0],
longitude: loc.coordinate[1]
}
вывод:
[
{
"name": "Vaes Dothrak",
"latitude": 54.16776,
"longitude": -6.096125
},
{
"name": "Winterfell",
"latitude": 54.368321,
"longitude": -5.581312
},
{
"name": "Dragonstone",
"latitude": 55.167801,
"longitude": -6.815096
}
]
Найти местоположение в радиусе
грамматика:
WITHIN()
Поиск местоположения в заданном радиусе от контрольной точки
FOR loc IN WITHIN(Locations, 53.35, -6.26, 200 * 1000)
RETURN {
name: loc.name,
latitude: loc.coordinate[0],
longitude: loc.coordinate[1]
}
вывод
[
{
"name": "Vaes Dothrak",
"latitude": 54.16776,
"longitude": -6.096125
},
{
"name": "Winterfell",
"latitude": 54.368321,
"longitude": -5.581312
}
]
Найти местоположения по расстоянию:
грамматика:
NEAR()或WITHIN()
Возвращает расстояние до контрольной точки, добавляя необязательный пятый параметр. Должна быть строка:
FOR loc IN NEAR(Locations, 53.35, -6.26, 3, "distance")
RETURN {
name: loc.name,
latitude: loc.coordinate[0],
longitude: loc.coordinate[1],
distance: loc.distance / 1000
}
вывод:
[
{
"name": "Vaes Dothrak",
"latitude": 54.16776,
"longitude": -6.096125,
"distance": 91.56658640314431
},
{
"name": "Winterfell",
"latitude": 54.368321,
"longitude": -5.581312,
"distance": 121.66399816395028
},
{
"name": "Dragonstone",
"latitude": 55.167801,
"longitude": -6.815096,
"distance": 205.31879386198324
}
]
Проблемы с AQL:
Вопрос 1: Как подсчитать и вернуть результаты запроса?
- Решение:
RETURN COUNT(FOR v IN visitors FILTER v.ip == "127.0.0.1" RETURN 1)