ArangoDB - совокупная сумма атрибутов-потомков в DAG
У меня есть список материалов, представленных в ArangoDB в виде ориентированного ациклического графа. Количество каждой части в ведомости материалов представлено по краям, в то время как названия частей представлены ключами узлов. Я хотел бы написать запрос, который проходит через DAG от узла-предка и суммирует количества каждой части по ее имени. Например, рассмотрим следующий график:
Qty: 2 Qty: 1
Widget +------> Gadget +------> Stuff
+ + Qty: 4
| Qty: 1 +---------> Thing
+----------------------------^
Widget
содержит два Gadgets
каждый из которых содержит один Stuff
и четыре Things
, Widget
также содержит один Thing
, Таким образом, я хотел бы написать AQL-запрос, который пересекает график, начиная с виджета, и возвращает:
{
"Gadget": 2,
"Stuff": 2,
"Thing": 9
}
я верю collect aggregate
может быть, мой друг здесь, но я еще не нашел правильного заклинания. Часть проблемы заключается в том, что все потомки количества детали должны быть умножены на их родительские количества. Как может выглядеть такой запрос, который эффективно выполняет суммирование для групп DAG глубины около 10 уровней?
1 ответ
На ум приходят три возможных варианта:
1.- вернуть значения из пути и затем суммировать данные на сервере приложений:
FOR v,e,p IN 1..2 OUTBOUND 'test/4719491'
testRel
RETURN {v:v.name, p:p.edges[*].qty}
Это возвращает Gadget 2, Stuff [2,1], Thing [2,4], Thing [1]
2. Перечислите ребра на пути, чтобы получить результаты напрямую:
FOR v,e,p IN 1..2 OUTBOUND 'test/4719491'
testRel
let e0 = p.edges[0].qty
let e1 = NOT_NULL(p.edges[1].qty,1)
collect itemName = v.name aggregate items = sum(e0 * e1)
Return {itemName: itemName, items: items}
Это правильно возвращает Gadget 2, Stuff 2, Thing 9.
Это, очевидно, требует, чтобы вы знали количество уровней до руки.
3.- Напишите пользовательскую функцию "умножение", аналогичную существующей функции "SUM", чтобы вы могли умножать значения массива. Запрос будет похож на это:
let vals = (FOR v,e,p IN 1..2 OUTBOUND 'test/4719491'
testRel
RETURN {itemName:v.name, items:SUM(p.edges[*].qty)})
for val in vals
collect itemName = val.itemName Aggregate items = sum(val.items)
return {itemName: itemName, items: items}
Таким образом, ваша функция заменит СУММУ во внутреннем суб-выборе. Вот документация по пользовательским функциям