Object Tree, Users, Privilege Query


In our system, objects are organized into single rooted hierarchies (trees). In the diagram, the gray circles represent objects. An edge, named CHILD represents the child objects of a parent object.

User’s are given access privilege to specific objects in the tree. Users in the diagram are represented by pink circles. An access privilege is represented by an edge named CAN_ACCESS from a user to an object.

Access privileges in our system are inherited.

I’m trying to write a query that would find the objects a given user has access privilege to, but does not have access privilege to an ancestor.

In the example diagram for the user U2, the query should result in [b, c]. U2 does have access to f, but f should be excluded from the results because U2 has access to b, which is an ancestor of f.


Just bumping this to the top. Any suggestions on a query that would do what I described?

It’s relatively trivial to list the objects U2 has a grant on using this query.

assets(func: eq(name, “U2”)) {
grant {

What I can’t figure out how to do is filter out “f” from the results, due to the fact that “f” has an ancestor “b” to which U2 also has a grant on. It seems like I’d need to @filter on grant but also recurse.

Hey @mburbidg, I used the following data-set to recreate the graph that you have here.

    set {
        _:root <child> _:b .
        _:root <child> _:a .
        _:a <child> _:c .
        _:b <child> _:d .
        _:b <child> _:e .
        _:e <child> _:f .
        _:u2 <can_access> _:f .
        _:u2 <can_access> _:b .
        _:u2 <can_access> _:c .

        _:root <name> "root" .
        _:b <name> "b" .
        _:c <name> "c" .
        _:d <name> "d" .
        _:e <name> "e" .
        _:f <name> "f" .
        _:u2 <name> "U2" .

After that the following query gives us what you are looking for.

  # Store accessible nodes for U2 in a variable.
  var(func: eq(name, "U2")) {
    accessible as can_access
  # Start from the accessible nodes and recursively find all their children. Store them in another variable.
  var(func: uid(accessible)) @recurse {
    allChildren as child
  # Filter out all accessible nodes which are also children of another accessible node.
  me(func: uid(accessible)) @filter(NOT uid(allChildren)) {

Let us know if that works for you.

Thanks Pawan. That works and gives me a better idea for constructing future queries.