Пользовательский фильтр/посетитель Arangodb для моего древовидного графа

У меня есть график с двумя определениями ребер, например:

isDepartment: [organisation] -> [organisation]
hasAccess: [user] -> [organisation]

Организации вложены в дерево (без циклов). Существует несколько организаций верхнего уровня без каких-либо входящих isDepartment ребер.

Пользователям предоставляется доступ к одной или нескольким организациям. Это могут быть организации верхнего уровня или организации, расположенные ниже по дереву. Если пользователь имеет доступ к организации, он имеет доступ ко всем дочерним организациям.

Я пытаюсь создать пользовательского посетителя или фильтр, который дает мне все доступные организации для пользователя, включая его путь к корню, а также свойство, доступны они или нет.

Например, возьмем следующую организационную структуру:

  • Root A
    • Dept. A.1
    • Отдел А.2
  • Root B
    • Dept. B.1
    • Отдел Б.2
    • Подотдел Б.2.1
  • Root C
    • Dept. C.1
    • Отдел С.2

Теперь возьмем пользователя, у которого есть доступ к Root A и Dept. B.2. Я хотел бы создать следующее дерево результатов:

  • Root A, accessible: true
    • Dept. A.1, accessible: true
    • Отдел A.2, доступный: правда
  • Root B, accessible: false
    • Dept. B.2, accessible: true
    • Подотдел B.2.1, доступный: правда

Обратите внимание, что Root C и Dept. B1 отсутствуют в результате, потому что они недоступны для пользователя, равно как и их дочерние элементы.

Также обратите внимание, что Root B включено, но помечено как not accessible. Это связано с тем, что пользователю предоставляется доступ только к дочернему элементу Root B, но не к самому корню.

Как я могу написать пользовательскую функцию/посетитель/фильтр, который выполнил это?


person Sander Marechal    schedule 02.11.2015    source источник


Ответы (1)


Это был действительно сложный вопрос, спасибо большое ;)

Вы можете решить эту проблему, добавив пользовательские функции в AQL и используя их в файле TRAVERSER.

Прежде всего я зарегистрировал две гостевые функции AQL через arangosh:

var aqlfunctions = require("org/arangodb/aql/functions");
aqlfunctions.register("myvisitor::indirectAccess", "function (config, result, vertex) { if(result.length === 0) {result.push({});} result[0][vertex._key] = {hasAccess: true};}")
aqlfunctions.register("myvisitor::noAccess", "function (config, result, vertex) { if (result.length === 0) {result.push({});} result[0][vertex._key] = {hasAccess: false};}")

Эти функции просто делают следующее:

  • myvisitor::indirectAccess будет использоваться для обхода дерева. Так как в AQL результатом всегда является массив, мы просто при первом документировании в него (при необходимости) сохраняем все данные. Затем мы присваиваем свойству вершин _key значение {hasAccess: true}.
  • myvisitor::noAccess будет использоваться для перемещения вверх по дереву и будет хранить '{hasAccess: false}` таким же образом.

Теперь мы можем выполнить следующий запрос, который использует этих посетителей:

FOR x IN GRAPH_NEIGHBORS(@graph, @userId, {direction: 'outbound'})
LET upwards = TRAVERSAL(organisation, isDepartment, x, 'inbound', {visitor: 'myvisitor::noAccess'})[0]
LET downwards = TRAVERSAL(organisation, isDepartment, x, 'outbound', {visitor: 'myvisitor::indirectAccess'})[0]
RETURN MERGE(upwards, downwards)

Краткое объяснение:

  1. Найдите организации, к которым у этого пользователя есть прямой доступ.
  2. Поднимитесь по дереву upwards и пометьте все как "нет доступа".
  3. Спуститесь по дереву downwards и пометьте все как "доступ".
  4. Объедините upwards и downwards.

Если вы хотите изменить формат результата, вам необходимо изменить функции зарегистрированного посетителя.

person mchacki    schedule 03.11.2015
comment
О, это выглядит очень хорошо. Спасибо, пойду пробовать :-) - person Sander Marechal; 04.11.2015
comment
Это не совсем правильно, но я к этому иду. Мне нужно добавить некоторую сортировку и вложение (или отступ на vertex.name), чтобы получить нужный мне результат. - person Sander Marechal; 04.11.2015