Мне также нужно было знать ответ на этот вопрос, поэтому вот решение, которое работает.
Я уверен, что код нужно будет настроить для вас и можно будет внести некоторые улучшения, пожалуйста, прокомментируйте соответствующим образом, если это необходимо для этого образца ответа.
Решение состоит в том, чтобы использовать микросервис Foxx, который поддерживает рекурсию и строит дерево. У меня есть проблема с циклическими путями, но я реализовал ограничение максимальной глубины, которое останавливает это, жестко закодированное до 10 в приведенном ниже примере.
Чтобы создать микросервис Foxx:
- Создайте новую папку (например, рекурсивное дерево)
- Создайте скрипты каталога
- Поместите файлы
manifest.json
и index.js
в корневой каталог.
- Поместите файл
setup.js
в каталог скриптов.
- Затем создайте новый zip-файл с этими тремя файлами (например,
Foxx.zip
)
- Перейдите в консоль администратора ArangoDB.
- Щелкните "Услуги" | Добавить услугу
- Введите соответствующую точку монтирования, например / мое / дерево
- Перейдите на вкладку Zip.
- Перетащите созданный файл
Foxx.zip
, он должен создать без проблем.
- Если вы получите сообщение об ошибке, убедитесь, что коллекции
myItems
и myConnections
не существуют, а граф с именем myGraph
не существует, так как он попытается создать их с образцами данных.
- Затем перейдите в консоль администратора ArangoDB, Services | / мое / дерево
- Нажмите на API
- Развернуть / tree / {rootId}
- Укажите параметр rootId для ItemA и нажмите «Попробовать».
- Вы должны увидеть результат из предоставленного корневого идентификатора.
Если rootId не существует, он ничего не возвращает.Если rootId не имеет дочерних элементов, он возвращает пустой массив для 'contains'. Если rootId имеет циклические значения 'contains', он возвращает вложенность до предела глубины, я бы хотел, чтобы был более чистый способ остановить это.
Вот три файла: setup.js (должны находиться в папке скриптов):
'use strict';
const db = require('@arangodb').db;
const graph_module = require("org/arangodb/general-graph");
const itemCollectionName = 'myItems';
const edgeCollectionName = 'myConnections';
const graphName = 'myGraph';
if (!db._collection(itemCollectionName)) {
const itemCollection = db._createDocumentCollection(itemCollectionName);
itemCollection.save({_key: "ItemA" });
itemCollection.save({_key: "ItemB" });
itemCollection.save({_key: "ItemC" });
itemCollection.save({_key: "ItemD" });
itemCollection.save({_key: "ItemE" });
if (!db._collection(edgeCollectionName)) {
const edgeCollection = db._createEdgeCollection(edgeCollectionName);
edgeCollection.save({_from: itemCollectionName + '/ItemA', _to: itemCollectionName + '/ItemB'});
edgeCollection.save({_from: itemCollectionName + '/ItemB', _to: itemCollectionName + '/ItemC'});
edgeCollection.save({_from: itemCollectionName + '/ItemB', _to: itemCollectionName + '/ItemD'});
edgeCollection.save({_from: itemCollectionName + '/ItemD', _to: itemCollectionName + '/ItemE'});
}
const graphDefinition = [
{
"collection": edgeCollectionName,
"from":[itemCollectionName],
"to":[itemCollectionName]
}
];
const graph = graph_module._create(graphName, graphDefinition);
}
mainfest.json (должен находиться в корневой папке):
{
"engines": {
"arangodb": "^3.0.0"
},
"main": "index.js",
"scripts": {
"setup": "scripts/setup.js"
}
}
index.js (должен находиться в корневой папке):
'use strict';
const createRouter = require('@arangodb/foxx/router');
const router = createRouter();
const joi = require('joi');
const db = require('@arangodb').db;
const aql = require('@arangodb').aql;
const recursionQuery = function(itemId, tree, depth) {
const result = db._query(aql`
FOR d IN myItems
FILTER d._id == ${itemId}
LET contains = (
FOR c IN 1..1 OUTBOUND ${itemId} GRAPH 'myGraph' RETURN { "_id": c._id }
)
RETURN MERGE({"_id": d._id}, {"contains": contains})
`);
tree = result._documents[0];
if (depth < 10) {
if ((result._documents[0]) && (result._documents[0].contains) && (result._documents[0].contains.length > 0)) {
for (var i = 0; i < result._documents[0].contains.length; i++) {
tree.contains[i] = recursionQuery(result._documents[0].contains[i]._id, tree.contains[i], depth + 1);
}
}
}
return tree;
}
router.get('/tree/:rootId', function(req, res) {
let myResult = recursionQuery('myItems/' + req.pathParams.rootId, {}, 0);
res.send(myResult);
})
.response(joi.object().required(), 'Tree of child nodes.')
.summary('Tree of child nodes')
.description('Tree of child nodes underneath the provided node.');
module.context.use(router);
Теперь вы можете вызвать конечную точку Foxx Microservice API, указав rootId, и она вернет полное дерево. Это очень быстро.
Пример вывода этого для ItemA:
{
"_id": "myItems/ItemA",
"contains": [
{
"_id": "myItems/ItemB",
"contains": [
{
"_id": "myItems/ItemC",
"contains": []
},
{
"_id": "myItems/ItemD",
"contains": [
{
"_id": "myItems/ItemE",
"contains": []
}
]
}
]
}
]
}
Вы можете видеть, что Item B содержит двух дочерних элементов, ItemC и ItemD, а затем ItemD также содержит ItemE.
Я не могу дождаться, пока ArangoDB AQL улучшит обработку путей переменной глубины в запросах стиля FOR v, e, p IN 1..100 OUTBOUND 'abc/def' GRAPH 'someGraph'
. Настраиваемые посетители не рекомендуются для использования в 3.x, но на самом деле они не были заменены чем-то более мощным для обработки запросов с подстановочными знаками на глубине вершины в пути или обработки команд стиля prune
или exclude
при обходе пути.
Хотелось бы получить комментарии / отзывы, если это можно упростить.
person
David Thomas
schedule
12.10.2016
for v, e, p in 1..3 inbound
и вернутьp
. Если вам нужна более конкретная информация, вы можете использоватьp.vertices[0], p.vertices[1], p.vertices[2]
. Оттуда вы можете структурировать свой возврат, чтобы отображать нужные вам значения, хотяp
уже находится в иерархическом формате. - person Nate Gardner   schedule 08.10.2016uniqueVertices : global
option в моем обходе) - person Alice Smith   schedule 11.10.2016p
не в иерархическом формате. Он просто содержит ребра и вершины (оба в формате массива). Мне нужно вернуть иерархическую структуру, даже если глубина неизвестна, поэтому я не могу работать сp.vertices[0], p.vertices[1], p.vertices[2]
- person Alice Smith   schedule 11.10.2016