Neo4j-如何在保存或更新相关节点时删除与其他节点的关系

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

我在我的应用程序中使用了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.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"});