Search code examples
javaneo4jspring-dataspring-data-neo4j

Spring Data Neo4J reference related nodes without overwriting them on save


I'm struggling to write this, so I may have to give an example to help explain the problem I'm experiencing.

Say we have nodes of three types (these nodes may have more relationships of their own, e.g. Product Family, has product manager):

  • Product
  • Product Family
  • Battery

With these relationships

  • A product can be be in 0 or more families
  • A product can have 0 or more batteries.

When using spring-data-neo4j and saving a new Product, I wish to include these relatiopnships, such as the batteries they require and the product family they belong to. However if I only supply say an ID rather then a fully populated object, it overwrites this object along with properties and relations accordingly.

This isn't great as it means that I have to end up sending a fully populated object, with all it's relations everytime I wish to save something, and some of these relations may go quite deep.

My domain is as follows:

@Node
public class Product {

   @Id
   @GeneratedValue(generatorClass = SnowflakeGenerator.class)
   private Long productId;

   private String name;

   @Relationship(type = "REQUIRES_BATTERY", direction = OUTGOING)
   private List<Battery> batteryList;

   @Relationship(type = "IN_FAMILY", direction = OUTGOING)
   private List<ProductFamily> productFamilyList;
}

@Node
public class Battery {

   @Id
   @GeneratedValue(generatorClass = SnowflakeGenerator.class)
   private Long batteryId;

   private String name;
}



@Node
public class ProductFamily {

   @Id
   @GeneratedValue(generatorClass = SnowflakeGenerator.class)
   private Long familyId;

   private String name;
}

This could very well by from coming from a Relational Database mindset and is a 'limitation' of using Neo4J.

TLDR When persisting somethign in Neo4J using spring-data how can I save just a relationship, rather than a whole related Node.


Solution

  • You can make use of projections in Spring Data Neo4j. (https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#projections) This gives you the option to put a "mask" on the object tree, you want to persist (and what should stay untouched).

    For example in your case:

    interface ProductProjection {
      // without defining e.g. String getName() here, SDN would not ever touch this property.
      List<BatteryProjection> getBatteryList();
      List<ProductFamilyProjection> getProductFamilyList();
    }
    interface BatteryProjection {
      String getName();
    }
    interface ProductFamilyProjection {
      String getName();
    }