So far, you have used Spring Data’s derived find, save, and delete methods against the database. However, there are times when you need something a little different. This is where you can write custom Cypher queries for read operations.
Defining a custom repository method
Currently you have only implemented the Spring Data’s out-of-the-box findAll()
, findById()
, save()
, and deleteById()
methods.
These methods implement a standard use case for querying and saving data.
When you need something specific, you can define your own methods, and write Cypher statements that query the data and map the results back to a custom method.
For instance, the findAll()
method works fine to pull the nodes in this movie graph, but what if you had a graph multiple times larger? Even at the current size, it is difficult to view all that data returned on the console. Instead, you could write a custom method to pull a random, smaller subset of the graph each time.
To modify the findAll()
method you will need to:
-
Add a new
Query
method to theMovieRepository
interface:-
Open the
MovieRepository.java
interface insrc/main/java/com/example/appspringdata
-
Import the
org.springframework.data.neo4j.repository.query.Query
class.javaimport org.springframework.data.neo4j.repository.query.Query;
-
Add a new
findMoviesSubset()
method that uses the@Query
annotation to run a Cypher statement.javainterface MovieRepository extends Neo4jRepository<Movie, String> { @Query("MATCH (m:Movie)<-[r:ACTED_IN]-(p:Person)" + "RETURN m, collect(r), collect(p) LIMIT 20;") Iterable<Movie> findMoviesSubset(); }
The interface returns an
Iterable<Movie>
.
-
-
Modify the
MovieController
class to call the new query:-
Open the
`MovieRepository.java
class. -
Update the existing
findAllMovie()
method to call the new query method.java@GetMapping() Iterable<Movie> findAllMovies() { return movieRepo.findMoviesSubset(); }
-
Full code for the MovieRepository
and MovieController
classes is available in the dropdown below.
Click to reveal the completed MovieRepository
and MovieController
class code
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.query.Query;
interface MovieRepository extends Neo4jRepository<Movie, String> {
@Query("MATCH (m:Movie)<-[r:ACTED_IN]-(p:Person)" +
"RETURN m, collect(r), collect(p) LIMIT 20;")
Iterable<Movie> findMoviesSubset();
}
@RestController
@RequestMapping("/movies")
public class MovieController {
private final MovieRepository movieRepo;
public MovieController(MovieRepository movieRepo) {
this.movieRepo = movieRepo;
}
@GetMapping()
Iterable<Movie> findAllMovies() {
return movieRepo.findMoviesSubset();
}
@GetMapping("/{movieId}")
Optional<Movie> findMovieById(@PathVariable String movieId) {
return movieRepo.findById(movieId);
}
@PostMapping("/save")
Movie save(@RequestBody Movie movie) {
return movieRepo.save(movie);
}
@DeleteMapping("/delete")
void delete(@RequestParam String movieId) {
movieRepo.deleteById(movieId);
System.out.println("Deleted movie with movieId: " + movieId);
}
}
RETURN aggregation
In the RETURN
statement for the query above, each Movie
node is returned with its collected ACTED_IN
relationships and Person
nodes. This is because the method expects Movie
nodes, and then aggregates the related entities (relationships and nodes) for each unique movie using Cypher’s implicit aggregation for each item listed in the RETURN
statement.
Testing the findMoviesSubset() custom method
Once you make the modifications above to your project’s interface (new custom query) and controller (call findMoviesSubset()
), test the new method by running the application and calling the /movies
endpoint. You should see a response with a subset of movies, each with their ACTED_IN
relationships and Person
nodes.
curl 'localhost:8080/movies'
To take this a step further, you can define one more custom method that uses a search parameter. This will be covered in the next lesson.
Summary
In this lesson, you learned how to write your own custom methods and queries to retrieve data from the database.
Next, you will complete a challenge that builds upon that skill to create custom queries and methods for writing data to the database.