Search code examples
neo4jspring-data-neo4jspring-data-neo4j-4

how to get an entity By a related object id when using spring data neo4j?


@NodeEntity    
public class Person {
  @GraphId private Long nodeId;
  private String name;
  private String addr;
  private int age;

  @Relationship(type="WATCH")
  private Set<Movie> movies;
}


@NodeEntity
public class Movie{
  @GraphId private Long nodeId;
  private String title;
  private int released;


  @Relationship(type="WATCH" ,direction = Relationship.INCOMING)
  private Person person;

  public Movie(){}
}


@RequestMapping(value = "/movieTest", method = RequestMethod.GET)
public Movie movieTest(){
    Movie movie =movieRepository.findOne(5078L,1);
    return movie;
}
public interface MovieRepository extends GraphRepository<Movie> {
}

I create a Person class and a Movie class ,Person "WATCH" Movie,Person has property "movies",and Movie has property "person",My purpose is to get Person by a movie id,but an "java.lang.StackOverflowError" exception happened when I call /movieTest API,because after findOne() executed , the result object movie has a sub-object person, and person has a sub-object movies ,then go to a endless loop, so what I wonder is how to deal this situation or what should I do when I need to get Person By a movie id?


Solution

  • Firstly we need to double check the model. In Cypher you are saying (:Person)-[:WATCH]->(:Movie). In your java code you are saying:

    1. A person can watch many movies:
    2. A movie can be watched by one person.

    In general a movie could be watched by many people though right? If that's the case the movie class should hold a collection of people (with the same mapping).

    If it's some sort of movie preview app where exactly 0..1 Persons can watch a movie and once it's watched no one else can watch it (or it gets updated so the last person who watched it is the person) then you have several options:

    1. You could add a custom query to your repository:

      public interface PersonRepository extends GraphRepository<Person> {
          @Query("MATCH (n:Person)-[r]->(m:Movie) WHERE ID(m) = {movieId} RETURN r")
          Person findByMovieId(@Param("movieId) Long id);
      }
      

      Returning the relationship means your person object should get hydrated with the watched movie.

    2. Simply retrieve the movie as you are with the findOne method and then get the person from it: movie.getPerson()