Neo4j-如何在保存或更新相关节点时删除与其他节点的关系
我在我的应用程序中使用了Neo4j(3.4.1版)和Spring-data-Neo4j(5.0.10.RELEASE)。我也在使用OGM 我有以下领域模型(车辆和零件): 车辆等级Neo4j-如何在保存或更新相关节点时删除与其他节点的关系,neo4j,cypher,spring-data-neo4j,neo4j-ogm,Neo4j,Cypher,Spring Data Neo4j,Neo4j Ogm,我在我的应用程序中使用了Neo4j(3.4.1版)和Spring-data-Neo4j(5.0.10.RELEASE)。我也在使用OGM 我有以下领域模型(车辆和零件): 车辆等级 @NodeEntity @Data @NoArgsConstructor public class Vehicle { @Id @GeneratedValue private Long id; @Relationship(type = "HAS_PART", direction = Relationship.OU
@NodeEntity
@Data
@NoArgsConstructor
public class Vehicle {
@Id
@GeneratedValue
private Long id;
@Relationship(type = "HAS_PART", direction = Relationship.OUTGOING)
private List<Part> parts = new ArrayList<>();
}
我能够为给定的车辆设置零件
,并使用spring数据Neo4j存储库界面将节点存储在Neo4j数据库中
Vehicle myVehicle = new Vehicle();
Part brake = new Part("brake");
Part accelerator= new Part("accelerator");
Part clutch= new Part("clutch");
myVehicle.setParts(Arrays.asList(brake, accelerator, clutch));
Vehicle vehicle = vehicleRepository.save(myVehicle);
System.out.println("vehicle = " + vehicle);
我可以使用Neo4j浏览器查看数据库中的车辆
和零件
节点,如下所示:
我面临的问题是在更新现有车辆的过程中。
我正在尝试更改车辆
的零件
。我的工作如下:
Vehicle myVehicle = vehicleRepository.findById(582L).get();
Part brake = new Part("brake");
Part accelerator= new Part("accelerator");
myVehicle.setParts(Arrays.asList(brake, accelerator));
Vehicle savedVehicle = vehicleRepository.save(myVehicle);
System.out.println("vehicle = " + savedVehicle);
在IDE调试会话中,我可以看到savedVehicle
对象(在VehiclerDepository
上调用save
后返回)只有两个部分“刹车”和“加速器”。它没有“离合器”部分,我希望它是这样的
但是,当我使用浏览器检查Neo4j数据库中的相同车辆对象时,我看到车辆对象仍然有3个部分(甚至“离合器”)
我无法理解为什么离合器
节点仍然与车辆
节点相关,因为我已覆盖该节点及其关系。另外,为什么savedVehicle
对象与数据库中的对象不同
有人能解释一下吗?另外,如何在保存/更新时删除与离合器
节点的HAS_PART
关系
问候,,
V了解发生了什么的一个好方法是添加logging.level.org.neo4j.ogm.drivers.bolt=DEBUG
到您的application.properties。这将为您提供日志中正在执行的实际密码。您可以看到,您的代码转换为如下所示的MERGE
语句
Request: UNWIND {rows} as row MERGE (n:`Vehicle`{name: row.props.name}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-1, props={name=Car}}]}
Request: UNWIND {rows} as row MERGE (n:`Part`{name: row.props.name}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params {type=node, rows=[{nodeRef=-3, props={name=brake}}, {nodeRef=-5, props={name=accelerator}}, {nodeRef=-7, props={name=clutch}}]}
MERGE
子句确保图形中存在模式。模式已经存在,或者需要创建它。它不会删除任何现有节点
说到解决方案,有几种不同的方法可以实现您所寻找的目标,最简单的解决方案是执行以下操作:
Part p = new Part("brake");
partRepository.delete(p);
但是,请注意,这将删除所有车辆节点上名为“brake”的所有零件。这可能不是你一直想要的。例如,您可能只想从名为汽车
的车辆上分离离合器
假设您在车辆标签上有名称
属性,您可以在代码中执行类似操作,从名为车辆
的车辆
上分离和删除离合器(如果您没有车辆名称,请使用id或其他唯一属性):
另一个选项是在VehiclerDepository中编写一个带有@Query
注释的方法,以执行以下查询的等效操作:
MATCH(n:Vehicle {name:"Car"})-[:HAS_PART]->(p:Part{ name:"brake"})
DETACH DELETE p
然后,您可以简单地从服务类调用它
有关示例,请参见
编辑:添加有关仅删除车辆和零件之间关系的更多信息
这可以通过在VehiclerRepository中编写自定义查询来完成,如下所示(我假设您在Vehicle上也有name属性,如果没有,您可以使用id而不是name):
现在,您可以从代码中调用它,例如:
vehicleRepository.detachPartFromVehicle("Car", "clutch");
这将导致删除HAS_PART
关系--离合器
零件将保留在图形中,但它将与车辆车辆
断开连接
此外,您可以通过将其转换为IN查询来断开多个零件的连接:
@Query("MATCH(n:Vehicle {name: {0}})-[r:HAS_PART]-(p:Part) WHERE p.name IN {1} DELETE r")
Vehicle detachPartFromVehicle(@Param("partName") String vehicleNameName, @Param("partNames") String[] partNames);
谢谢@Bajal。你们的解释太夸张了。它执行合并
以检查关系是否存在,如果不存在则创建一个关系。它不会删除任何关系。我可以通过删除现有节点并保存更新的节点来解决问题。我必须将id
设置为null
,尽管Neo4j没有用相同的id保存节点。它将节点保存为一个全新的节点(在我的情况下这是正常的)。但是,一个仍然没有回答的问题是,为什么save
返回的实体只显示2个部分
节点,而不是数据库中的3个节点。这太误导人了。基于@Bajal的回答和他的查询,我决定探索是否可以通过扩展他的查询来实现更新行为,这将删除旧零件,添加任何新零件,并返回更新的车辆。以下是我的相同尝试:将['seat']作为新零件
将新零件作为新零件展开
匹配(r:Vehicle),其中id(r)=639
合并(r)-[:HAS_PART]>(:PART{name:newPart})
与r可选匹配(r)-[rel HAS_PART]-(p:PART),其中p.name位于['brake']
删除rel
与r匹配q=(r)-()
返回节点(q)、关系(q)
@Query("MATCH(n:Vehicle {name: {0}})-[r:HAS_PART]-(p:Part{ name:{1}}) DELETE r")
Vehicle detachPartFromVehicle(@Param("partName") String vehicleNameName, @Param("partName") String partName);
vehicleRepository.detachPartFromVehicle("Car", "clutch");
@Query("MATCH(n:Vehicle {name: {0}})-[r:HAS_PART]-(p:Part) WHERE p.name IN {1} DELETE r")
Vehicle detachPartFromVehicle(@Param("partName") String vehicleNameName, @Param("partNames") String[] partNames);
vehicleRepository.detachPartFromVehicle("Car", new String[] {"clutch", "brake"});