我也需要知道這個問題的答案,所以這裏有一個解決方案。
我確定代碼需要爲您定製,並且可以做一些改進,請對此樣例答案進行相應評論。
解決方案是使用支持遞歸和構建樹的Foxx Microservice。我遇到的問題是圍繞循環路徑,但是我實現了一個最大深度限制來阻止這個問題,在下面的例子中硬編碼爲10。
要創建福克斯的microService:
- 創建一個新的文件夾(如遞歸樹)
- 創建目錄的腳本
- 將文件
manifest.json
和index.js
到根目錄
- 廣場腳本目錄中的文件
setup.js
- 然後創建一個新的zip文件,其中包含這三個文件(例如
Foxx.zip
)
- 導航到ArangoDB管理控制檯
- 單擊服務|添加服務
- 輸入適當的掛載點,例如, /我的/樹
- 點擊郵編選項卡上
- 在您創建的
Foxx.zip
拖動文件,它應該建立一個沒有問題
- 如果你得到一個錯誤,保證藏品
myItems
和myConnections
不存在,並且曲線圖稱爲myGraph
不存在,因爲它會嘗試使用示例數據創建它們。
- 然後導航到ArangoDB管理控制檯,服務| /我的/樹
- 點擊API
- 展開/樹/ {rootId}
- 提供意達的rootId參數,然後單擊「試一試」
- 你應該看到的結果,從提供的根ID 。
如果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);
現在你可以調用佛xx Microservice API終點,提供rootId它將返回完整的樹。這很快。
本作意達的輸出的例子是:
{
"_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 in 1..3 inbound'並返回'p'。如果你想要更具體,你可以使用'p.vertices [0],p.vertices [1],p.vertices [2]'。從那裏你可以構造你的返回來顯示你想要的值,儘管'p'已經是分層格式。 –
已知最大嵌套深度了嗎?還是它是遞歸的,沒有可預測的深度? –
爲什麼結果必須是分層的?它是否應該防止結果集中的重複? – CoDEmanX