首页 > 解决方案 > 在 cypher 中,仅返回具有最近关系的节点

问题描述

与另一个问题相关但从关系的另一端接近。

这是场景。我正在为一个居住或曾经居住在一个或多个不同地点的人建模。关系中包括他们搬入时的开始日期(表示为自纪元以来的毫秒数)。

    (:Person{name:'bill'}) -[:livesAt {since:1111000}]->(:Place{name:'apartmentA'})    
    (:Person{name:'bill'}) -[:livesAt {since:2222000}]->(:Place{name:'apartmentB'})
    (:Person{name:'john'}) -[:livesAt {since:3333000}]->(:Place{name:'apartmentA'})
    (:Person{name:'chris'}) -[:livesAt {since:1100000}]->(:Place{name:'apartmentC'})
    (:Person{name:'chris'}) -[:livesAt {since:1122000}]->(:Place{name:'apartmentA'})

我想编写一个查询,返回仍然居住在给定位置的人员节点。如果 livingAt 关系在该人的所有关系中“自”以来最大,则他们仍居住在某个位置。

我正在尝试这样的事情:

MATCH (:Place {name: 'apartmentA'})<-[r]-(p:Person)
WITH max(r.since) as most_recent, p.name as pname
MATCH (t:Person {name:pname}) -[e]->(l:Place)
WITH t,l
ORDER BY e.since DESC
return t,l

如果我的查询与上面的示例一起使用,给定位置“apartmentA”,我希望得到 john 和 chris。

标签: neo4jcypher

解决方案


为了找到你想要的东西,你必须确保你过滤到那些没有 :livesAt 关系的人,因为他们有更大的自属性(表明他们现在住在其他地方)到不同的位置。这很重要,因为他们可能住在那个地方,搬到别处,然后又搬回来。

我们可以使用 Neo4j 4.x 中的存在子查询来更好地控制描述我们不想存在的模式。

MATCH (loc:Place {name: 'apartmentA'})<-[r:livesAt]-(p:Person)
WITH loc, max(r.since) as most_recent, p
WHERE NOT EXISTS {
    MATCH (p) -[r:livesAt]->(other)
    WHERE r.since > most_recent AND other <> loc
}
RETURN p.name

您也可以考虑对其进行改造,与他们当前的住所保持 :currentResidence 关系,并在他们移动时更新(删除旧的,创建新的)。这是您已经拥有的 :livesAt 关系的补充(我假设您将这些关系用于其他查询)。这使您可以非常快速地根据当前居住地执行检查和匹配,而无需进行任何额外的过滤。

编辑:

如果您不想使用存在子查询,我们可以使用模式的 OPTIONAL MATCH 代替,并且只过滤到另一个节点为空的结果,这意味着不存在这样的模式:

MATCH (loc:Place {name: 'apartmentA'})<-[r:livesAt]-(p:Person)
WITH loc, max(r.since) as most_recent, p
OPTIONAL MATCH (p) -[r:livesAt]->(other)
WHERE r.since > most_recent AND other <> loc
WITH p, other
WHERE other IS NULL
RETURN p.name

推荐阅读