Optional Lesson
This lesson is optional and will not count towards your achievement.
To view the completed code, check out the 15-person-profile
branch.
If you click on a Person card anywhere on the website, you will be taken to a Person profile. This API call is the same regardless of whether the person is an actor, director, or both.
We have already implemented the methods that populate the methods in the MovieService
to get a list of movies that the person has either acted in or directed.
But if you take a look at the PeopleService
, you will see two methods that need to be implemented to complete this page:
-
findById() - should find a person by their ID.
-
getSimilarPeople() - should return a list of similar people who are commonly connected to the same movies.
src/services/people.service.js
→
findById()
The findById()
method is currently hardcoded to return information about Al Pacino.
async findById(id) {
// TODO: Find a user by their ID
return pacino
}
You will update this method to run the following cypher statement in a read transaction.
MATCH (p:Person {tmdbId: $id})
RETURN p {
.*,
actedCount: count { (p)-[:ACTED_IN]->() },
directedCount: count { (p)-[:DIRECTED]->() }
} AS person
Parameters in Neo4j Browser
To run this query in Neo4j Sandbox, you will have to define a parameter in your Neo4j Browser session.
To do so, you can use the :param
command before running the Cypher statement to set a parameter for the duration of your Neo4j Browser session.
For example, to view Kevin Bacon, you can set the id
parameter to "4724":
:param id: "4724"
The query will return the properties for the person with the corresponding tmdbId
, along with a count of the number of movies that the person has acted in and directed.
Your Task
-
Modify the
findById()
method to query Neo4j and return details for the requested person. -
The returned object should include counts of the number of movies that the person has acted in or directed.
-
If no records are returned, the method will throw a
NotFoundError
. -
Remember to close the session and use the
toNativeTypes()
function to convert the object into native JavaScript types.
Click here to reveal the final findById()
method.
async findById(id) {
// Open a new database session
const session = this.driver.session()
// Get a list of people from the database
const res = await session.executeRead(
tx => tx.run(`
MATCH (p:Person {tmdbId: $id})
RETURN p {
.*,
actedCount: count { (p)-[:ACTED_IN]->() },
directedCount: count { (p)-[:DIRECTED]->() }
} AS person
`, { id })
)
// Close the session
await session.close()
const [row] = res.records
return toNativeTypes(row.get('person'))
}
getSimilarPeople()
The getSimilarPeople()
method should return a paginated list of similar people based on their second degree connections - either people who have acted in or have directed the person.
async getSimilarPeople(id, limit = 6, skip = 0) {
// TODO: Get a list of similar people to the person by their id
return people.slice(skip, skip + limit)
}
There could be a more clever algorithm for finding similar people by weighting the type of relationship differently, but for now, the following query will find a list of similar people based on the number of relationships in common.
MATCH (:Person {tmdbId: $id})-[:ACTED_IN|DIRECTED]->(m)<-[r:ACTED_IN|DIRECTED]-(p)
WITH p, collect(m {.tmdbId, .title, type: type(r)}) AS inCommon
RETURN p {
.*,
actedCount: count { (p)-[:ACTED_IN]->() },
directedCount: count {(p)-[:DIRECTED]->() },
inCommon: inCommon
} AS person
ORDER BY size(person.inCommon) DESC
SKIP 0
LIMIT 6
Parameters in Neo4j Browser
To run this query in Neo4j Sandbox, you will have to define a parameter in your Neo4j Browser session.
To do so, you can use the :param
command before running the Cypher statement to set a parameter for the duration of your Neo4j Browser session.
For example, to view Kevin Bacon, you can set the id
parameter to "4724":
:param id: "4724"
Your Task
-
Modify the
getSimilarPeople()
method to query Neo4j and return a list of similar people. -
The returned objects should include a list of actors and an
inCommon
property to show how the two people are related. -
Remember to close the session and use the
toNativeTypes()
function within amap()
function onres.records
to convert the values to native JavaScript types.
Click here to reveal the final getSimilarPeople()
method.
async getSimilarPeople(id, limit = 6, skip = 0) {
// Get a list of similar people to the person by their id
const session = this.driver.session()
const res = await session.executeRead(
tx => tx.run(`
MATCH (:Person {tmdbId: $id})-[:ACTED_IN|DIRECTED]->(m)<-[r:ACTED_IN|DIRECTED]-(p)
WITH p, collect(m {.tmdbId, .title, type: type(r)}) AS inCommon
RETURN p {
.*,
actedCount: count { (p)-[:ACTED_IN]->() },
directedCount: count {(p)-[:DIRECTED]->() },
inCommon: inCommon
} AS person
ORDER BY size(person.inCommon) DESC
SKIP $skip
LIMIT $limit
`, { id, limit: int(limit), skip: int(skip) })
)
await session.close()
return res.records.map(row => toNativeTypes(row.get('person')))
}
Testing
To test that this functionality has been correctly implemented, run the following code in a new terminal session:
npm run test 15
The test file is located at test/challenges/15-person-profile.spec.js
.
Are you stuck? Click here for help
If you get stuck, you can see a working solution by checking out the 15-person-profile
branch by running:
git checkout 15-person-profile
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
According to our algorithm, who is the most similar person to Francis Ford Coppola?
As part of the test suite, the final test will log the name of the most common person to Francis Ford Coppola according to our Cypher statement.
Paste the name of the person the box below without quotes or whitespace and click Check Answer.
-
✓ Frederic Forrest
Hint
You can also find the answer by running the following Cypher statement:
MATCH (:Person {tmdbId: '1776'})-[:ACTED_IN|DIRECTED]->(m)<-[r:ACTED_IN|DIRECTED]-(p)
WITH p, collect(m) AS inCommon
RETURN p.name
ORDER BY size(inCommon) DESC
LIMIT 1
Copy the answer without any double quotes or whitespace.
Lesson Summary
In this Challenge, you have implemented the final methods in the PeopleService
.