Finding Genre Details

When the user clicks a genre in the list, they are taken to a list of movies for that genre. This list is populated by an API request to /api/genres/[name], for example http://localhost:3000/api/genres/Comedy.

The find() method the the GenreService accepts one argument, the name of the genre, and should return the information about the genre, along with a count of movies and a poster image.

java
neoflix/services/GenreService.java
public Map<String,Object> find(String name) {
    // TODO: Open a new session
    // TODO: Get Genre information from the database
    // TODO: Throw a 404 Error if the genre is not found
    // TODO: Close the session

    return genres.stream()
            .filter(genre -> genre.get("name").equals(name))
            .findFirst()
            .orElseThrow(() -> new RuntimeException("Genre "+name+" not found"));
}

In this challenge, you will modify the method to run the following Cypher statement in a read transaction:

cypher
Finding Genre Details
MATCH (g:Genre {name: $name})<-[:IN_GENRE]-(m:Movie)
WHERE m.imdbRating IS NOT NULL AND m.poster IS NOT NULL AND g.name <> '(no genres listed)'
WITH g, m
ORDER BY m.imdbRating DESC

WITH g, head(collect(m)) AS movie

RETURN g {
    .name,
    movies: count { (g)<-[:IN_GENRE]-() },
    poster: movie.poster
} AS genre

What does this query do?

This query uses the MATCH clause for a Genre node with the name passed through with the function call as a parameter. The query then finds the highest rated movie with a poster property and uses that image as the background to the card in the UI.

The size() function returns the number of incoming IN_GENRE relationships for each the Genre node.

Your Task

  • Modify the find() method on the GenreService to call the Neo4j database and return details for a genre.

  • The name variable should be passed to the run() call as a parameter.

  • If no records or more than one record are found, a NotFoundError should be thrown by using the single() method on Result.

  • Remember to close the session and use the toMap() function to convert the genre values to native Java types.

Working Solution

Click here to view the completed find() method.
java
neoflix/services/GenreService.java
public Map<String,Object> find(String name) {
    // Open a new Session, close automatically at the end
    try (var session = driver.session()) {
        // Get a list of Genres from the database
        var query = """
                MATCH (g:Genre {name: $name})<-[:IN_GENRE]-(m:Movie)
                WHERE m.imdbRating IS NOT NULL
                AND m.poster IS NOT NULL
                AND g.name <> '(no genres listed)'
                WITH g, m
                ORDER BY m.imdbRating DESC

                WITH g, head(collect(m)) AS movie

                RETURN g {
                  link: '/genres/'+ g.name,
                  .name,
                  movies: count { (g)<-[:IN_GENRE]-() },
                  poster: movie.poster
                } AS genre
              """;
        var genre = session.executeRead(
                tx -> tx.run(query, Values.parameters("name", name))
                        // Throw a NoSuchRecordException if the genre is not found
                        .single().get("genre").asMap());
        // Return results
        return genre;
    }
}

Testing

To test that this functionality has been correctly implemented, run the following code in a new terminal session:

sh
Running the test
mvn test -Dtest=neoflix._10_GenreDetailsTest

The test file is located at src/test/java/neoflix/_10_GenreDetailsTest.java.

Are you stuck? Click here for help

If you get stuck, you can see a working solution by checking out the 10-genre-details branch by running:

sh
Check out the 10-genre-details branch
git checkout 10-genre-details

You may have to commit or stash your changes before checking out this branch. You can also click here to expand the Support pane.

Verifying the Test

How many movies are in the Action genre?

After the test has succeeded, the test suite will log the count of movies in the Action genre to the console.

Enter the number of movies below and click Check Answer.

  • ✓ 1545

Hint

You can also find the answer by running the following Cypher statement:

cypher
MATCH (g:Genre {name: "Action"})
RETURN count { (g)<-[:IN_GENRE]-() }

Lesson Summary

In this Challenge, you modified the find() method in the GenreService to retrieve genre information from Neo4j.

In the next Challenge, you will update multiple methods in the MovieService that return a paginated list of movies.