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}

Таким образом, ваша функция заменит СУММУ во внутреннем суб-выборе. Вот документация по пользовательским функциям

Другие вопросы по тегам