Slavko Rihtarič
Slavko Rihtarič

Reputation: 13

Neo4j Cypher query not working as expected

I need a bit of help. I have a graph. It's for project management app

The Day node is represented as follows. The Occupancy node has a START and an optional END relationship to the Day node and the Employee node has the OCCUPIES relationship to the Occupancy node. the Occupancy node has the OCCUPIES relationship to the Project node.

So my question is: get all the employees that occupied the project on a specific date.

The query that i have so far:

match (employee:Employee)-[:OCCUPIES]->(o:Occupancy)-[:OCCUPIES]->(project:Project{uuid:"ed409308-3202-495f-b834-ef1e8d5039d6"})
with employee, o
match(:Year{value:2018})-[:CONTAINS]->(:Month {value:10})-[:CONTAINS]->(day:Day {value:10})
with day, employee, o
match(o)-[:START]-(start:Day)-[:NEXT*0..365]->(day)
optional match(o)-[:END]-(end:Day)
optional match(day)-[:NEXT*0..300]->(end)
return employee

But that does not work. It gives me all the employees regardless if theirs occupancy ended before the date. Example in the graph above all the occupancies start on the 10.april.2018, half of them end on 1.june.2018. In the query i got the date 10.october.2018.

Can somebody help me with this?

regards Slavko

Upvotes: 0

Views: 72

Answers (3)

Slavko Rihtarič
Slavko Rihtarič

Reputation: 13

Thank for your answers. It helped me allot. The query that i wrote based on your help:

match(:Year{value:{y}})-[:CONTAINS]->(:Month {value:{m}})-[:CONTAINS]->(day:Day {value:{d}})
            with day
            match (employee:Employee)-[:OCCUPIES]->(o:Occupancy)-[:OCCUPIES]->(project:Project{uuid:{project}})
            with day, employee, project, o
            match (o)-[:START]->(start:Day)
            with day, employee, project, o, start
            match p=shortestpath((start)-[:NEXT*0..365]->(day))
            with day, employee, project, o, start, p
            WHERE all(day IN NODES(p) WHERE NOT (o)-[:END]->(day))
            optional match(employee)-[:WORKS]->(dayshift:Shift{shifttype:0})-[:WORKDAY]->(day)  
            optional  match(dayshift)-[:WORKS]->(project)
            optional match(employee)-[:WORKS]->(nightshift:Shift{shifttype:1})-[:WORKDAY]->(day)  
            optional  match(nightshift)-[:WORKS]->(project)            
            return employee, dayshift, nightshift

But i have one more problem. If the Occupancy starts on lets say 1.april.2018 and ends 1.april.2018 so it was one day long. for this case the query above does not work because it has a END relationship.

Any suggestion how to solve that?

Upvotes: 0

cybersam
cybersam

Reputation: 67019

  1. The following clause matches all occupancies that started up to a year before the desired start date (including the desired start date). This is probably why all employees were returned.

    MATCH (o)-[:START]-(start:Day)-[:NEXT*0..365]->(day)
    

    If you wanted to find occupancies that started on a specific day, you should have used this:

    MATCH (o)-[:START]-(day)
    

    Or, if you actually wanted to find occupancies that started on a specific day or within a year after that date, you should have used the following (I will assume this is what you wanted):

    MATCH (o)-[:START]-(start:Day)<-[:NEXT*0..365]-(day)
    
  2. Your OPTIONAL MATCH clauses currently have no effect at all on whether an employee is returned. (Also, those clauses only match end dates that are within 300 days after the start day -- I will assume this is a requirement of your use case even though it is not stated in your question.)

The following query tries to address both issues, and may work for you:

MATCH (employee:Employee)-[:OCCUPIES]->(o:Occupancy)-[:OCCUPIES]->(project:Project{uuid:"ed409308-3202-495f-b834-ef1e8d5039d6"})
MATCH (:Year{value:2018})-[:CONTAINS]->(:Month {value:10})-[:CONTAINS]->(day:Day {value:10})
MATCH (o)-[:START]-(start:Day)<-[:NEXT*0..365]-(day)
OPTIONAL MATCH (o)-[:END]-(end:Day)
OPTIONAL MATCH p=(day)-[:NEXT*0..300]->(end)
RETURN CASE WHEN p IS NULL THEN employee ELSE NULL END AS employee;

Note: All the NEXT relationship hops needed, per candidate employee, to satisfy this query (up to 665) seem expensive. You may want to come up with a more efficient data model (but if you need help with that, it would require a new question).

Upvotes: 0

logisima
logisima

Reputation: 7478

Can you try this query :

MATCH 
     (:Year{value:2018})-[:CONTAINS]->(:Month {value:10})-[:CONTAINS]->(day:Day {value:10}),
    (employee:Employee)-[:OCCUPIES]->(o:Occupancy),
    (o)-[:OCCUPIES]->(project:Project{uuid:"ed409308-3202-495f-b834-ef1e8d5039d6"}),
    (o)-[:START]->(start:Day),
    p=shortestpath((start)-[:NEXT*]->(day))
WHERE all(day IN NODES(p) WHERE NOT (o)-[:END]->(day))
RETURN employee

The trick here is that I search the shortestpath between the starting day, and the day you give to the query. For each node on this path, I'm checking that is there is no END relationship to the Occupation.

So normally, you should only have Occupation nodes you are searching.

Upvotes: 0

Related Questions