密码:在取消缠绕第二个列表并执行不返回任何结果的匹配之后,在取消缠绕第二个列表之前声明的列表将变为空

时间:2019-09-05 14:29:35

标签: neo4j cypher

我在noe4j db中具有以下情形: 可以根据某些条件将任务分配给不同的用户。有一个可选标准(某些任务有针对用户位置的过滤器,有些则没有)。 我需要为用户找到所有任务(如果他们具有位置过滤器,那么我还需要检查用户的位置,如果他们不符合其余条件,那么我也需要检查用户的位置。)

我试图收集与强制性条件匹配的任务,然后过滤不需要可选过滤器的任务,然后过滤需要可选过滤器的任务并匹配当前用户,最后合并两个列表。

您还可以建议一种更有效的方法吗?

这是一个最小的示例(当然,在UNWIND之后,我的比赛更为复杂)

WITH [{a: 'test'}, {a: 'a', b: 'b'}] AS initialList

WITH [i IN initialList WHERE i.b IS NULL] AS itemsWithoutB, initialList

UNWIND initialList AS item
MATCH (item) WHERE item.a IS NULL

RETURN COLLECT(item) + itemsWithoutB

我希望在这里返回itemsWithoutB的内容,但是没有记录(Response: [])。

请注意,如果在UNWIND之后执行的MATCH实际上返回了一些记录,那么也会返回itemsWithoutB的内容。

例如:

WITH [{a: 'test'}, {a: 'a', b: 'b'}] AS initialList

WITH [i IN initialList WHERE i.b IS NULL] AS itemsWithoutB, initialList

UNWIND initialList AS item
MATCH (item) WHERE item.a IS NOT NULL

RETURN COLLECT(item) + itemsWithoutB

这将返回:

╒═════════════════════════════════════════════╕
│"COLLECT(item) + itemsWithoutB"              │
╞═════════════════════════════════════════════╡
│[{"a":"test"},{"a":"a","b":"b"},{"a":"test"}]│
└─────────────────────────────────────────────┘

Neo4j版本:Enterprise 3.5.6

请问我在这里想念什么?

---编辑---

我在这里添加一个更复杂的示例,更接近实际情况:

生成初始数据:

MERGE (d:Device {code: 'device1', latitude:90.5, longitude: 90.5})-[:USED_BY]->(u:User {name: 'user1'})-[:WORKS_IN]->(c:Country {code: 'RO'})<-[targets:TARGETS]-(:Task {name: 'task1', latitude: 90.5, longitude: 90.5, maxDistance: 1000, maxMinutesAfterLastInRange: 99999})<-[:IN_RANGE {timestamp: datetime()}]-(d)

MERGE (c)<-[:TARGETS]-(:Task {name: 'task2'})

MERGE (c)<-[:TARGETS]-(:Task {name: 'task4', latitude: 10.5, longitude: 10.5, maxDistance: 1, maxMinutesAfterLastInRange: 99999})

CREATE (:User  {name: 'user2'})-[:WORKS_IN]->(:Country {code: 'GB'})<-[:TARGETS]-(:Task {name: 'task3'})

在此示例中为neo4j console link

我希望能够使用相同的查询来查找任何用户的任务(应该为user1返回task1和task2,为user2返回task3,为两个用户都不返回task4)

以下查询适用于user1,但如果我将用户名过滤器更改为“ user2”,则该查询不起作用:

MATCH (user:User {name: "user1"})-[:WORKS_IN]->(country) 
OPTIONAL MATCH (device:Device)-[:USED_BY]->(user)
WITH country, device
MATCH (task:Task)-[:TARGETS]->(country) 
WITH COLLECT(task) AS filteredTasks, device

WITH [t IN filteredTasks WHERE t.latitude IS NULL OR t.longitude IS NULL] AS matchedTasksWithoutLocationFilter, filteredTasks, device

UNWIND filteredTasks AS task
MATCH (device)-[inRange:IN_RANGE]->(task)
WHERE task.maxMinutesAfterLastInRange IS NOT NULL 
AND duration.between(datetime(inRange.timestamp), datetime()).minutes <= task.maxMinutesAfterLastInRange

RETURN COLLECT(task) + matchedTasksWithoutLocationFilter AS matchedTasks

1 个答案:

答案 0 :(得分:0)

根据新信息更新答案

我认为您可以一口气做到这一点,而无需列表理解。

   MATCH (user: User {name: "user1" })-[:WORKS_IN]->(country)<-[:TARGETS]-(task: Task)
OPTIONAL MATCH (task)<-[inRange: IN_RANGE]-(device: Device)-[:USED_BY]->(user)
    WITH task, inRange
   MATCH (task)
   WHERE (task.latitude IS NULL OR task.longitude IS NULL)
      OR (inRange IS NOT NULL AND 
          task.maxMinutesAfterLastInRange IS NOT NULL AND 
          duration.between(datetime(inRange.timestamp), datetime()).minutes <= task.maxMinutesAfterLastInRange)
  RETURN task

对于user1:

╒══════════════════════════════════════════════════════════════════════╕
│"task"                                                                │
╞══════════════════════════════════════════════════════════════════════╡
│{"name":"task2"}                                                      │
├──────────────────────────────────────────────────────────────────────┤
│{"name":"task1","maxDistance":1000,"maxMinutesAfterLastInRange":99999,│
│"latitude":90.5,"longitude":90.5}                                     │
└──────────────────────────────────────────────────────────────────────┘

对于user2:

╒════════════════╕
│"task"          │
╞════════════════╡
│{"name":"task3"}│
└────────────────┘

原始答案

当您的MATCH不返回任何节点(在该示例中,所有节点都具有a属性)时,其余查询无用可做-就像是内部失败加入传统的SQL数据库。

如果切换到OPTIONAL MATCH,则无论itemsWithoutB是否有效,您都将看到MATCH的结果。我知道您的示例是人工合成的,所以我不确定这是否是您想要的-在您的示例中,COLLECT(item)将从itemUNWIND,并且结果OPTIONAL MATCH中的基本上无关紧要。仍然,假设这些是具有真实查询的真实节点:

WITH [{a: 'test'}, {a: 'a', b: 'b'}] AS initialList
WITH [i IN initialList WHERE i.b IS NULL] AS itemsWithoutB, initialList
UNWIND initialList AS item
OPTIONAL MATCH (item) WHERE item.a IS NULL
RETURN COLLECT(item) + itemsWithoutB

您可能需要做一些进一步的工作来消除重复结果。