neo4j - 在 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。
解决方案
为了找到你想要的东西,你必须确保你过滤到那些没有 :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
推荐阅读
- regex - 如何在 Angular 2+ 中动态更改我的正则表达式验证器?
- javascript - 谷歌地图:在功能中获取点击位置
- azure - 使用 C# 和 Azure Functions 2.x 将函数应用设置存储和加载为 JSON 对象
- ssis - DTC 事务无法启动。这可能是因为 MSDTC 服务未运行
- java - 在树中查找值
- r - 每个分类列的 Sparklyr/Dplyr 频率
- java - 按属性有条件地启动 bean 组
- c# - EF Core:将 DbContext 实体拆分为多个表
- android - Android 7.0 的 onTextChanged TextWatcher 问题
- javascript - 检查用户是否在 div 的底部