Skip to content

Commit

Permalink
Optimised Cypher queries in Neo4j example (#25973)
Browse files Browse the repository at this point in the history
Thank you for including a Neo4j example!

This PR rewrites the Cypher queries using a [pattern comprehension](https://neo4j.com/docs/cypher-manual/current/syntax/lists/#cypher-pattern-comprehension) which will make them more performant and removes the need for the `collect(DISTINCT ...)` step.
  • Loading branch information
adam-cowley authored Jul 19, 2021
1 parent 7fea8f3 commit 9774d9b
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 31 deletions.
2 changes: 1 addition & 1 deletion examples/with-neo4j/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"start": "next start"
},
"dependencies": {
"neo4j-driver": "4.1.1",
"neo4j-driver": "^4.3.1",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2",
Expand Down
2 changes: 1 addition & 1 deletion examples/with-neo4j/pages/actor/[name].js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function Actor() {
<h2>Information</h2>
<div>
<strong>Born: </strong>
{data.actor.born.low}
{data.actor.born}
</div>
</div>
<div className="movies">
Expand Down
6 changes: 3 additions & 3 deletions examples/with-neo4j/pages/api/actors/[name].js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ export default async function handler(req, res) {
async (transaction) => {
const cypher = `
MATCH (actor:Person {name: $actorName})
MATCH (m:Movie)
WHERE (actor)-[:ACTED_IN]->(m)
RETURN actor {.*, movies: collect(m.title)} as actor
RETURN actor {.*,
movies: [ (actor)-[:ACTED_IN]->(m) | m.title ]
} as actor
`

const actorTxResponse = await transaction.run(cypher, { actorName })
Expand Down
9 changes: 4 additions & 5 deletions examples/with-neo4j/pages/api/movies/[title].js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,10 @@ export default async function handler(req, res) {
async (transaction) => {
const cypher = `
MATCH (movie:Movie {title: $movieTitle})
MATCH (actor:Person)
WHERE (movie)<-[:ACTED_IN]-(actor)
MATCH (director:Person)
WHERE (movie)<-[:DIRECTED]-(director)
RETURN movie {.*, actors: collect(DISTINCT actor.name), directed: collect(DISTINCT director.name)} as movie
RETURN movie {.*,
actors: [ (actor)-[:ACTED_IN]->(movie) | actor.name ],
directed: [ (director)-[:DIRECTED]->(movie) | director.name ]
} as movie
`

const movieTxResponse = await transaction.run(cypher, {
Expand Down
10 changes: 5 additions & 5 deletions examples/with-neo4j/pages/api/movies/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ export default async function handler(req, res) {
async (transaction) => {
const cypher = `
MATCH (movie:Movie)
MATCH (actor:Person)
WHERE (movie)<-[:ACTED_IN]-(actor)
MATCH (director:Person)
WHERE (movie)<-[:DIRECTED]-(director)
RETURN movie {.*, actors: collect(DISTINCT actor.name), directed: collect(DISTINCT director.name)} as movie
RETURN movie {.*,
actors: [ (movie)<-[:ACTED_IN]-(actor) | actor.name ],
directed: [ (movie)<-[:DIRECTED]-(director) | director.name ]
} as movie
ORDER BY movie.title ASC
`

const moviesTxResponse = await transaction.run(cypher)
Expand Down
16 changes: 3 additions & 13 deletions examples/with-neo4j/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,11 @@ export default function Home() {
<tr className="movie" key={movie.title}>
<th>{index + 1}</th>
<td>
<Link
href="/movie/[title]"
as={{
pathname: `/movie/${encodeURIComponent(movie.title)}`,
}}
>
<Link href={`/movie/${encodeURIComponent(movie.title)}`}>
<a className="link">{movie.title}</a>
</Link>
</td>
<td>{movie.released.low}</td>
<td>{movie.released}</td>
<td>{movie.tagline}</td>
<td>
<ul>
Expand All @@ -64,12 +59,7 @@ export default function Home() {
<ul>
{movie.actors.map((actor) => (
<li key={actor}>
<Link
href="/actor/[name]"
as={{
pathname: `/actor/${encodeURIComponent(actor)}`,
}}
>
<Link href={`/actor/${encodeURIComponent(actor)}`}>
<a className="link">{actor}</a>
</Link>
</li>
Expand Down
11 changes: 9 additions & 2 deletions examples/with-neo4j/pages/movie/[title].js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,17 @@ export default function Movie() {
</div>
<div>
<strong>Released: </strong>
{data.movie.released.low}
{data.movie.released}
</div>
</div>
<div className="actors">
<h2>Actors</h2>
{data.movie.actors.map((actor) => (
<div key={actor}>{actor}</div>
<div key={actor}>
<Link key={actor} href={`/actor/${encodeURIComponent(actor)}`}>
<a className="link">{actor}</a>
</Link>
</div>
))}
</div>
<div className="directors">
Expand Down Expand Up @@ -81,6 +85,9 @@ export default function Movie() {
.movie {
margin-bottom: 2rem;
}
.movie a {
text-decoration: underline;
}
.back {
padding: 1rem 0;
}
Expand Down
7 changes: 6 additions & 1 deletion examples/with-neo4j/util/neo4j.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ const defaultOptions = {
export default function getDriver() {
const { uri, username, password } = defaultOptions
if (!driver) {
driver = neo4j.driver(uri, neo4j.auth.basic(username, password))
// Note: There is a disparity between Neo4j (Java) Integers and JavaScript integers
// I have used `disableLosslessIntegers` to remove the need to call `.toNumber()` on each integer value
// For more info see: https://github.com/neo4j/neo4j-javascript-driver/#numbers-and-the-integer-type
driver = neo4j.driver(uri, neo4j.auth.basic(username, password), {
disableLosslessIntegers: true,
})
}

return driver
Expand Down

0 comments on commit 9774d9b

Please sign in to comment.