简体   繁体   中英

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

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.

  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).

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?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM