Browsing Genres

If you click on the Genres link in the main navigation, you will be taken to a list of Genres. This list is populated by the API route at http://localhost:3000/api/genres, with the list being produced by the AllAsync() method within the GenreService.

c#
Neoflix/Services/GenreService.cs
public Task<Dictionary<string, object>[]> AllAsync()
{
    // TODO: Open a new session
    // TODO: Get a list of Genres from the database
    // TODO: Close the session

    return Task.FromResult(Fixtures.Genres.ToArray());
}

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

cypher
Listing Genres
MATCH (g:Genre)
WHERE g.name <> '(no genres listed)'

CALL {
  WITH g
  MATCH (g)<-[:IN_GENRE]-(m:Movie)
  WHERE m.imdbRating IS NOT NULL AND m.poster IS NOT NULL
  RETURN m.poster AS poster
  ORDER BY m.imdbRating DESC LIMIT 1
}

RETURN g {
  .*,
  movies: count { (g)<-[:IN_GENRE]-(:Movie) },
  poster: poster
}
ORDER BY g.name ASC

Your Task

  • Modify the AllAsync() method on the GenreService to query Neo4j and return a list of properties ordered by genre name.

  • Each genre should have a name, the number of movies listed in that genre (movies), and a poster image (from the most popular movie in that genre).

  • Remember to close the session and use the ToListAsync() function result.list to convert the values to native C# types.

Working Solution

Click here to view the completed AllAsync() method.
c#
Neoflix/Services/GenreService.cs
public async Task<Dictionary<string, object>[]> AllAsync()
{
    await using var session = _driver.AsyncSession();
    return await session.ExecuteReadAsync(async tx =>
    {
        var query = @"
            MATCH (g:Genre)
            WHERE g.name <> '(no genres listed)'
            CALL {
                WITH g
                MATCH (g)<-[:IN_GENRE]-(m:Movie)
                WHERE m.imdbRating IS NOT NULL
                AND m.poster IS NOT NULL
                RETURN m.poster AS poster
                ORDER BY m.imdbRating DESC LIMIT 1
            }
            RETURN g {
                .*,
                movies: count { (g)<-[:IN_GENRE]-(:Movie) },
                poster: poster
            } as genre
            ORDER BY g.name ASC";
        var cursor = await tx.RunAsync(query);
        var records = await cursor.ToListAsync();

        return records
            .Select(x => x["genre"].As<Dictionary<string, object>>())
            .ToArray();
    });
}

Testing

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

sh
Running the test
dotnet test --logger "console;verbosity=detailed" --filter "Neoflix.Challenges._09_GenreList"

The test file is located at Neoflix.Challenges/09-GenreList.cs.

Are you stuck? Click here for help

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

sh
Check out the 09-genre-list branch
git checkout 09-genre-list

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

Which genre has the highest movie count?

After the test has succeeded, the test suite will log the name of the genre with the greatest number of movies.

Enter the name of the genre below and click Check Answer.

  • ✓ Drama

Hint

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

cypher
MATCH (g:Genre)
RETURN g.name ORDER BY count{ (g)<-[:IN_GENRE]-() } DESC LIMIT 1

Copy the answer without any quotes or whitespace.

Lesson Summary

In this Challenge, you updated the GenreService to retrieve a list of genres from the database.

In the next Challenge, you will update the GenreService to query Neo4j to find the details of an individual genre.