Search code examples
neo4jcypher

NEO4J query clause in a tree like membership graph


So I have this graph structure where many "Top level" and subspaces spaces can exist like this: enter image description here

I have the next cypher query:

MATCH (user:User {auth_token: $auth_token}) 
      MATCH (space:Space)
      WHERE (
        (NOT (space)<-[:PARENT_OF]-(:Space) AND (user)-[:MEMBER_OF]->(space) AND space.pod_state IN ['active', 'pending'] AND space.pod_type IN ['standard', 'readonly'])
        OR
        (EXISTS {MATCH (parent:Space)-[:PARENT_OF*]->(space)<-[:MEMBER_OF]-(user) WHERE NOT (user)-[:MEMBER_OF]->(parent) AND space.pod_state IN ['active', 'pending'] AND space.pod_type IN ['standard', 'readonly']})
      )
      RETURN space

What I need in this case is the list of spaces (blue) that a user can see (yellow) So:

  • Simon DDD should only see "TOP LEVEL SPACE" even when he is also a member of "LEVEL 2 SPACE" he should see the space with the highest level in every hierarchy.
  • Simon LALALA on the other hand should see "LEVEL 2 SPACE" since he is only a member of that space.

In the query provided SIMON DDD is getting both "TOP LEVEL SPACE" and "LEVEL 2 SPACE" SIMON LALALA is okay since he is only a member of one space in the path

Also, the query works fine if, for example, SIMON DDD is a member of the "LEVEL 1 SPACE A" because the "NOT" clause on the query will work, which means if the user is a MEMBER OF every space in the path only shows the top level space


Solution

  • This query will return a list of the highest level ("visible") spaces of which a User is a member:

    MATCH (user:User {auth_token: $auth_token})-[:MEMBER_OF]->(space)
    WITH user, COLLECT(space) AS spaces
    RETURN user, REDUCE(vs = [], s IN spaces |
      CASE WHEN NONE(a IN [(s)<-[:PARENT_OF*]-(ancestor)|ancestor] WHERE a IN spaces)
      THEN vs + s
      ELSE vs END
    ) AS visibleSpaces
    

    It ignores the pod_state property, as you did not specify how that should be used.