我在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
答案 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)
将从item
到UNWIND
,并且结果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
您可能需要做一些进一步的工作来消除重复结果。