7.4. Hyperedges

7.4.1. Find Groups
7.4.2. Find all groups and roles for a user
7.4.3. Find common groups based on shared roles

Imagine a user being part of different groups. A group can have different roles, and a user can be part of different groups. He also can have different roles in different groups apart from the membership. The association of a User, a Group and a Role can be referred to as a HyperEdge. However, it can be easily modeled in a property graph as a node that captures this n-ary relationship, as depicted below in the U1G2R1 node.

Figure 7.2. Graph


7.4.1. Find Groups

To find out in what roles a user is for a particular groups (here Group2), the following query can traverse this HyperEdge node and provide answers.

Query. 

START n=node:node_auto_index(name = 'User1')
MATCH n-[:hasRoleInGroup]->hyperEdge-[:hasGroup]->group, hyperEdge-[:hasRole]->role
WHERE group.name = "Group2"
RETURN role.name

The role of User1 is returned:

Result

role.name
1 row

"Role1"


Try this query live. (1) {"name":"U1G2R1"} (2) {"name":"Role2"} (3) {"name":"Group1"} (4) {"name":"Group2"} (5) {"name":"Role1"} (6) {"name":"Role"} (7) {"name":"User1"} (8) {"name":"U1G1R2"} (9) {"name":"Group"} (1)-[:hasRole]->(5) {} (1)-[:hasGroup]->(4) {} (2)-[:isA]->(6) {} (3)-[:canHave]->(5) {} (3)-[:canHave]->(2) {} (3)-[:isA]->(9) {} (4)-[:canHave]->(2) {} (4)-[:canHave]->(5) {} (4)-[:isA]->(9) {} (5)-[:isA]->(6) {} (7)-[:in]->(3) {} (7)-[:in]->(4) {} (7)-[:hasRoleInGroup]->(1) {} (7)-[:hasRoleInGroup]->(8) {} (8)-[:hasRole]->(2) {} (8)-[:hasGroup]->(3) {} start n=node:node_auto_index(name = 'User1') match n-[:hasRoleInGroup]->hyperEdge-[:hasGroup]->group, hyperEdge-[:hasRole]->role where group.name = "Group2" return role.name

7.4.2. Find all groups and roles for a user

Here, find all groups and the roles a user has, sorted by the name of the role.

Query. 

START n=node:node_auto_index(name = "User1")
MATCH n-[:hasRoleInGroup]->hyperEdge-[:hasGroup]->group, hyperEdge-[:hasRole]->role
RETURN role.name, group.name
ORDER BY role.name asc

The groups and roles of User1 are returned:

Result

role.namegroup.name
2 rows

"Role1"

"Group2"

"Role2"

"Group1"


Try this query live. (1) {"name":"U1G2R1"} (2) {"name":"Role2"} (3) {"name":"Group1"} (4) {"name":"Group2"} (5) {"name":"Role1"} (6) {"name":"Role"} (7) {"name":"User1"} (8) {"name":"U1G1R2"} (9) {"name":"Group"} (1)-[:hasRole]->(5) {} (1)-[:hasGroup]->(4) {} (2)-[:isA]->(6) {} (3)-[:canHave]->(5) {} (3)-[:canHave]->(2) {} (3)-[:isA]->(9) {} (4)-[:canHave]->(2) {} (4)-[:canHave]->(5) {} (4)-[:isA]->(9) {} (5)-[:isA]->(6) {} (7)-[:in]->(3) {} (7)-[:in]->(4) {} (7)-[:hasRoleInGroup]->(1) {} (7)-[:hasRoleInGroup]->(8) {} (8)-[:hasRole]->(2) {} (8)-[:hasGroup]->(3) {} start n=node:node_auto_index(name = "User1") match n-[:hasRoleInGroup]->hyperEdge-[:hasGroup]->group, hyperEdge-[:hasRole]->role return role.name, group.name order by role.name asc

7.4.3. Find common groups based on shared roles

Assume a more complicated graph:

  1. Two user nodes User1, User2.
  2. User1 is in Group1, Group2, Group3.
  3. User1 has Role1, Role2 in Group1; Role2, Role3 in Group2; Role3, Role4 in Group3 (hyper edges).
  4. User2 is in Group1, Group2, Group3.
  5. User2 has Role2, Role5 in Group1; Role3, Role4 in Group2; Role5, Role6 in Group3 (hyper edges).

The graph for this looks like the following (nodes like U1G2R23 representing the HyperEdges):

Figure 7.3. Graph


To return Group1 and Group2 as User1 and User2 share at least one common role in these two groups, the query looks like this:

Query. 

START u1=node:node_auto_index(name = 'User1'),      u2=node:node_auto_index(name = 'User2')
MATCH u1-[:hasRoleInGroup]->hyperEdge1-[:hasGroup]->group,
      hyperEdge1-[:hasRole]->role,
      u2-[:hasRoleInGroup]->hyperEdge2-[:hasGroup]->group,
      hyperEdge2-[:hasRole]->role
RETURN group.name, count(role)
ORDER BY group.name ASC

The groups where User1 and User2 share at least one common role:

Result

group.namecount(role)
2 rows

"Group1"

1

"Group2"

1


Try this query live. (1) {"name":"U2G2R34"} (2) {"name":"U1G3R34"} (3) {"name":"User2"} (4) {"name":"User1"} (5) {"name":"Role6"} (6) {"name":"U1G2R23"} (7) {"name":"Role4"} (8) {"name":"Role5"} (9) {"name":"U2G1R25"} (10) {"name":"Group1"} (11) {"name":"Role2"} (12) {"name":"Group2"} (13) {"name":"Role3"} (14) {"name":"Group3"} (15) {"name":"U1G1R12"} (16) {"name":"Role1"} (17) {"name":"U2G3R56"} (1)-[:hasGroup]->(12) {} (1)-[:hasRole]->(13) {} (1)-[:hasRole]->(7) {} (2)-[:hasGroup]->(14) {} (2)-[:hasRole]->(13) {} (2)-[:hasRole]->(7) {} (3)-[:hasRoleInGroup]->(9) {} (3)-[:hasRoleInGroup]->(1) {} (3)-[:hasRoleInGroup]->(17) {} (4)-[:hasRoleInGroup]->(15) {} (4)-[:hasRoleInGroup]->(6) {} (4)-[:hasRoleInGroup]->(2) {} (6)-[:hasGroup]->(12) {} (6)-[:hasRole]->(11) {} (6)-[:hasRole]->(13) {} (9)-[:hasGroup]->(10) {} (9)-[:hasRole]->(11) {} (9)-[:hasRole]->(8) {} (15)-[:hasGroup]->(10) {} (15)-[:hasRole]->(16) {} (15)-[:hasRole]->(11) {} (17)-[:hasGroup]->(14) {} (17)-[:hasRole]->(8) {} (17)-[:hasRole]->(5) {} start u1=node:node_auto_index(name = 'User1'), u2=node:node_auto_index(name = 'User2') match u1-[:hasRoleInGroup]->hyperEdge1-[:hasGroup]->group, hyperEdge1-[:hasRole]->role, u2-[:hasRoleInGroup]->hyperEdge2-[:hasGroup]->group, hyperEdge2-[:hasRole]->role return group.name, count(role) order by group.name ASC