Connecting to Neo4j from a node.js ap
In this tutorial, we will walk through how to set up a quick node.js-based app and connect it to a local Neo4j instance, so we can start querying data.
A few assumptions about skill level
I assume you have the basic knowledge to set up a node project
Node js is installed on your machine
A running instance of Neo4j Desktop or container ready to accept connections
Basic knowledge of the Cypher query language
Step 1: A very basic node script
Open your text editor of choice, mine happens to be the ubiquitous VS Code, and create a new folder called node-loves-neo4j. Here we will initialise our new script and install a few packages to help us connect to Neo4j.
mkdir node-loves-neo4j
cd node-loves-neo4j
npm init -y
Now that we have our basic node.js package setup, let's go ahead and create the index file and install the neo4j-driver required for us to talk to the database.
touch index.js
npm install neo4j-driver
Step 2: Setting up the script
Open index.js in your favourite editor and add the following snippet of code. In the first line we are importing the neo4j-driver, so we can use it. Make sure your local Neo4j instance is running on port :7687, and has the neo4j-user and password setup (otherwise fill in credentials that match your configuration)
// index.js
// import the neo4j-driver module
import neo4j from 'neo4j-driver'
// create credentials to access the local database instance
const credentials = {
host: 'neo4j://localhost:7687',
user: 'neo4j',
password: '<your-secret-password>'
}
// here we create the driver we will be using to access, using basic auhtentication
const _driver = neo4j.driver(credentials.host, neo4j.auth.basic(credentials.user, credentials.password))
Step 3: Making it easy to query
Now that we have our driver set up and ready to connect, let us create a little helper function to make our queries as clean as possible. Below the driver create the following function. Be sure to note that the function is async to allow us to await the promise returned from Neo.
// index.js
// our function will take a string query and an object of parameters.
// For this we will only use the queries, but I included the params
// for good measure
const cypher = async (query, params) => {
try {
// first we will create a session
const session = _driver.session()
// query the database for results
const result = await session.run(query, params)
// check if we had a result (possibly add some better error handling here)
if (result.records.length == 0)
return []
// since we know know that we have data
} catch(err) {
console.error('error', err)
} finally {
await session.close()
return result.records || []
}
}
Step 4: Create a few nodes
Great, now we have a function that we can use to make calls, so let's try it out in action by creating a small graph of rock and metal bands and the countries they are from. Here we are using Neo4j's built-in function UNWIND to iterate over a list of band names and create a node for each band, setting its name.
// American bands
await cypher(`
UNWIND ['Metallica', 'Slayer', 'Megadeth', 'Guns N Roses'] as bandName
MERGE (b:Band { name: bandName })
MERGE (c:Country { name: 'USA' })
MERGE (b)-[:ORIGINATES_FROM]->(c)
`)
// Aussie bands
await cypher(`
UNWIND ['AC/DC', 'Wolfmother'] as bandName
MERGE (b:Band { name: bandName })
MERGE (c:Country { name: 'Australia' })
MERGE (b)-[:ORIGINATES_FROM]->(c)
`)
// British bands
await cypher(`
UNWIND ['Black Sabbath', 'Iron Maiden', 'The Who', 'The Rolling Stones'] as bandName
MERGE (b:Band { name: bandName })
MERGE (c:Country { name: 'England' })
MERGE (b)-[:ORIGINATES_FROM]->(c)
`)
Notice here, in stead of using the CREATE-keyword to create our nodes and relationships, we use the MERGE-keyword. Merge will either create the node if it does not exist or skip if it does. While a bit slower, MERGE allows us to rerun our script over and over, without having to worry about clashing relationships.
Step 5: Query the data
Now that we have a few nodes and relationships to work with, let's query and get a list of band names along with the country they are from and order them by the band's name.
// will return on the form { name: '<name>', country: '<country>' }
const result = await cypher(`
MATCH (b:Band)-->(c:Country)
RETURN b.name as name, c.name as country
ORDER BY b.name
`)
// consloe.log each row from the result
result.forEach((r,i) => console.log(`Band ${i}: ${r.name}, ${r.country}`))
// Result:
// Band 0: AC/DC, Australia
// Band 1: Black Sabbath, England
// Band 2: Guns N Roses, England
// ...
As you can probably tell, the results are stored in an array and each item is an object with the named properties we selected from our graph. This makes it easy to grab the result and work with the object as we do with any other javascript object.
Step 6: Run the script
Last thing we need is to actually run our script, so let's go ahead and to that now.
$ node index.js
Band 0: AC/DC, Australia
Band 1: Black Sabbath, England
Band 2: Guns N Roses, England
Conclusion
So, there you have it. A simple script, that lets you connect to Neo4j and submit queries in an easy package so you can focus on your model and your app.
Hope you have enjoyed it and happy graph'ing :)
/Anders
Subscribe to my newsletter
Read articles from Anders Kirkeby directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Anders Kirkeby
Anders Kirkeby
I am a CTO and Web Architect with an interest in what drives high performing dev teams and how to construct scalable web apps without FAANG-level infrastructure.