Мне также нужно было знать ответ на этот вопрос, так что вот решение, которое работает.
Я уверен, что код должен быть настроен для вас и может сделать некоторые улучшения, пожалуйста, прокомментируйте соответственно, если это подходит для ответа на этот образец.
Решение заключается в использовании Foxx Microservice, который поддерживает рекурсию и создает дерево. Проблема, которая у меня есть, связана с циклами цикла, но я применил максимальный предел глубины, который останавливает это, жестко закодированный до 10 в приведенном ниже примере.
Чтобы создать Foxx Microservice:
- Создать новую папку (например, рекурсивного дерева)
- создаются сценарии директории
- Поместите файлы
manifest.json
и index.js
в корневой каталог
- Place файл
setup.js
в каталоге скриптов
- Затем создайте новый zip-файл с этими тремя файлами в нем (например,
Foxx.zip
)
- Перейти к администратору консоли ArangoDB
- Нажмите на Услуги | Добавить услугу
- Введите подходящую точку монтирования, например./Моя/дерево
- Нажмите на вкладке Zip
- Перетащите файл
Foxx.zip
вы создали, он должен создать без проблем
- Если вы получите сообщение об ошибке, убедитесь, коллекции
myItems
и myConnections
не существует, и граф myGraph
не существует, поскольку он попытается создать их с образцами данных.
- Затем перейдите к консоли администратора ArangoDB, Services |/Моя/дерево
- Нажмите на API
- Развернуть/дерево/{RootID}
- Обеспечить параметр RootID из Itema и нажмите кнопку 'Попробуйте It Out'
- Вы должны увидеть результат, из предоставленного корневого идентификатора ,
Если RootID не существует, то он ничего не возвращает Если RootID не имеет детей, он возвращает пустой массив для «содержит» Если RootID имеет цикл «содержит» значения, он возвращает вложенности до я хочу, чтобы был лучший способ остановить это.
Вот три файла: 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);
Теперь вы можете вызвать Fo xx конечная точка API Microservice, предоставляющая rootId, которая вернет полное дерево. Это очень быстро.
Пример вывода этого для Itema является:
{
"_id": "myItems/ItemA",
"contains": [
{
"_id": "myItems/ItemB",
"contains": [
{
"_id": "myItems/ItemC",
"contains": []
},
{
"_id": "myItems/ItemD",
"contains": [
{
"_id": "myItems/ItemE",
"contains": []
}
]
}
]
}
]
}
Вы можете видеть, что пункт B состоит из двух детей, ItemC и ItemD, а затем ItemD также содержит ItemE.
Я не могу дождаться, пока ArangoDB AQL улучшит обработку переменных путей глубины в запросах стиля FOR v, e, p IN 1..100 OUTBOUND 'abc/def' GRAPH 'someGraph'
. Пользовательские посетители не были рекомендованы для использования в 3.x, но на самом деле их не заменили чем-то мощным для обработки запросов диких карточек на глубине вершины в пути или обработки команд стиля prune
или exclude
при обходе пути.
Хотел бы иметь комментарии/отзывы, если это можно упростить.
Пара соответствующих методов, которые могут вам помочь: 'для v, e, p в 1..3 входящего и возврата' p'. Если вы хотите более конкретно, вы можете использовать 'p.vertices [0], p.vertices [1], p.vertices [2]'. Оттуда вы можете структурировать свое возвращение, чтобы отобразить нужные значения, хотя 'p' уже находится в иерархическом формате. –
Известна ли максимальная глубина гнездования? Или это рекурсивный без предсказуемой глубины? –
Почему результат должен быть иерархическим? Предполагается ли предотвратить дублирование в результирующем наборе? – CoDEmanX