Neo4j Cypher:在解开第二个列表之前声明的列表在解开第二个列表并执行不返回结果的匹配后变为空

Neo4j Cypher:在解开第二个列表之前声明的列表在解开第二个列表并执行不返回结果的匹配后变为空,neo4j,cypher,Neo4j,Cypher,我在noe4j数据库中有以下场景: 有些任务可以根据某些标准分配给不同的用户。有一个可选的标准(有些任务有用户位置的过滤器,有些没有)。 我需要找到一个用户的所有任务(如果他们有一个位置过滤器,我也需要检查用户的位置,如果他们没有,我只匹配其余的条件) 我尝试收集符合强制条件的任务,然后筛选不需要可选筛选器的任务,然后筛选需要可选筛选器的任务,并匹配当前用户,最后合并两个列表 你能建议一种更有效的方法吗 这里有一个简单的例子(当然,我在放松后有更复杂的匹配) 我希望在这里返回itemsWitho

我在noe4j数据库中有以下场景: 有些任务可以根据某些标准分配给不同的用户。有一个可选的标准(有些任务有用户位置的过滤器,有些没有)。 我需要找到一个用户的所有任务(如果他们有一个位置过滤器,我也需要检查用户的位置,如果他们没有,我只匹配其余的条件)

我尝试收集符合强制条件的任务,然后筛选不需要可选筛选器的任务,然后筛选需要可选筛选器的任务,并匹配当前用户,最后合并两个列表

你能建议一种更有效的方法吗

这里有一个简单的例子(当然,我在放松后有更复杂的匹配)

我希望在这里返回
itemsWithoutB
的内容,但我没有得到任何记录(
Response:[]

请注意,如果展开后完成的匹配确实返回了一些记录,那么
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版本:企业版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'})
MERGE(d:Device{code:'device1',纬度:90.5,经度:90.5})->(u:User{name:'user1})->(c:Country{code:'RO})根据新信息更新了答案
我认为你可以一次完成这项工作,而不需要理解列表

   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
对于用户2:

╒════════════════╕
│"task"          │
╞════════════════╡
│{"name":"task3"}│
└────────────────┘
原始答案 当您的
MATCH
没有返回任何节点时(在该示例中,所有节点都有
a
属性),查询的其余部分就没有工作要做了——有点像传统SQL数据库中失败的内部联接

如果切换到
可选匹配
,则无论
匹配
是否有效,您都会看到来自
项目的结果。我知道您的示例是合成的,所以我不确定您是否在追求这个目标-在您的示例中,
收集(项目)
将从
展开
中删除
项目
,而
可选匹配的结果基本上是无关的。尽管如此,假设这些是具有真实查询的真实节点:

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
您可能需要做一些进一步的工作来消除重复结果。

根据新信息更新了答案 我认为你可以一次完成这项工作,而不需要理解列表

   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
对于用户2:

╒════════════════╕
│"task"          │
╞════════════════╡
│{"name":"task3"}│
└────────────────┘
原始答案 当您的
MATCH
没有返回任何节点时(在该示例中,所有节点都有
a
属性),查询的其余部分就没有工作要做了——有点像传统SQL数据库中失败的内部联接

如果切换到
可选匹配
,则无论
匹配
是否有效,您都会看到来自
项目的结果。我知道您的示例是合成的,所以我不确定您是否在追求这个目标-在您的示例中,
收集(项目)
将从
展开
中删除
项目
,而
可选匹配的结果基本上是无关的。尽管如此,假设这些是具有真实查询的真实节点:

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

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

谢谢@Pablisimo,我用一个更复杂的例子更新了我的问题,更类似于我的真实场景。同样的情况也适用-如果您将所有匹配更改为可选匹配(除了用户的第一个匹配),您将得到“user1”的任务1和任务2,“user2”的任务3更进一步抱歉(我有一个顽固不化的孩子,他现在不让我编码,所以我不能模拟它…)你可能会发现两个查询的联合可能读起来更好,并为你做重复数据消除我也会给联合一个尝试,谢谢你的建议。OPTIONAL确实会在这里返回预期的结果,但是位置过滤器实际上不再应用。例如,如果我添加另一个名为“task4”的任务,其中包含位置详细信息,但不在用户范围内,那么查询也会意外地匹配该任务:
match(c:Country{code:'RO})MERGE(c)确实是这样。非常感谢,@pablissimoThanks@Pablissimo,我已经用一个更复杂的例子更新了我的问题,更类似于我的真实场景。同样的情况也适用-如果您将所有匹配更改为可选匹配(除了用户的第一个匹配),您将得到任务1和任务2“user1”,任务3“user2”抱歉,更进一步(我有一个顽固不化的蹒跚学步的孩子,他现在不让我编码,所以我不能模拟它…)您可能会发现,由两个查询组成的联合可能阅读效果更好,并且可以为您执行重复数据消除。我也会尝试联合,谢谢您的建议。OPTIONAL确实会在此处返回预期结果,但位置筛选器实际上将不再应用。例如,如果我添加另一个名为“task4”的任务使用位置详细信息,但不在用户范围内,查询也会意外地匹配该位置:
match(c:Country{code:'RO'})MERGE(c)确实是这样。非常感谢,@pablissimo