Neo4j handbook for Nodejs and Python
Published on 06/05/2025
5 min read
In category
technical
A lightning‑fast handbook of the only commands you need to stand up, populate, and query a Neo4j graph from JavaScript (Node.js) or Python. Copy, paste, ship.
Basic Concepts
- Node – an entity/record; can hold multiple labels (e.g.,
:Person,:Customer). - Relationship – a directed, typed edge between two nodes (e.g.,
[:KNOWS]); stores its own properties. - Property – key–value data on nodes or relationships (
name,age,since). - Path – an ordered chain of nodes & relationships; assign it with
p = (a)-[:REL]->(b). - Cypher – the query language; core verbs:
MATCH,CREATE,MERGE,SET/REMOVE,DELETE,RETURN/WITH,WHERE. - Indexes – speed up look‑ups on frequently filtered properties (
CREATE INDEX ...). - Constraints – enforce integrity (e.g., uniqueness:
... REQUIRE email IS UNIQUE). - Transaction – ACID wrapper around one or more operations (
session.write_transaction(...)). - APOC / GDS – plugin libraries providing utilities (APOC) and graph algorithms (GDS) for power users.
1 Setup & Connection Setup & Connection
Install Drivers
- Node.js
npm i neo4j-driver - Python
pip install neo4j
Connect (Bolt URI)
// Node.js
const neo4j = require('neo4j-driver');
const driver = neo4j.driver('neo4j://localhost:7687',
neo4j.auth.basic('neo4j', 'password'));
const session = driver.session({ database: 'neo4j' });# Python
from neo4j import GraphDatabase
driver = GraphDatabase.driver('neo4j://localhost:7687',
auth=("neo4j", "password"))
with driver.session() as session:
...Tip Use
neo4j+s://for AuraDB or any TLS‑encrypted endpoint.
Close when done:
await session.close();
await driver.close();session.close()
driver.close()2 Create Nodes (Labels ≈ Tables)
await session.run(
'CREATE (p:Person {name:$name, age:$age})',
{ name: 'Alice', age: 30 }
);session.run(
"CREATE (p:Person {name:$name, age:$age})",
{"name": "Alice", "age": 30}
)Use parameters ($name)—never string‑concatenate user input.
3 Create Relationships
await session.run(
'MATCH (a:Person {name:$from}), (b:Person {name:$to})\n'
+ 'CREATE (a)-[:KNOWS {since:$y}]->(b)',
{ from: 'Alice', to: 'Bob', y: 2020 }
);session.run(
"MATCH (a:Person {name:$from}), (b:Person {name:$to}) "
"CREATE (a)-[:KNOWS {since:$y}]->(b)",
{"from": "Alice", "to": "Bob", "y": 2020}
)4 Read / Match Patterns
Basic lookup
MATCH (p:Person {name:$name}) RETURN p;Traversal (friends of friends)
MATCH (p:Person {name:$name})-[:KNOWS]->()-[:KNOWS]->(fof)
RETURN DISTINCT fof.name;Retrieve in code:
const res = await session.run(query,{name:'Alice'});
res.records.forEach(r=>console.log(r.get(0)));for record in session.run(query, name="Alice"):
print(record[0])5 Filtering, Ordering, Pagination
MATCH (p:Person)
WHERE p.age > $minAge
RETURN p.name, p.age
ORDER BY p.name
SKIP $skip LIMIT $limit;Params {minAge:30, skip:10, limit:5}
6 Aggregations
MATCH (p:Person)-[:KNOWS]->(f:Person)
RETURN p.name, count(f) AS friends
ORDER BY friends DESC;Collect list:
MATCH (p)-[:KNOWS]->(f)
RETURN p.name, collect(f.name) AS friendList;7 Shortest Path
MATCH p = shortestPath((a:Person {name:$a})-[:KNOWS*..5]-(b:Person {name:$b}))
RETURN nodes(p) AS hops;8 Schema: Indexes & Constraints
// Uniqueness
CREATE CONSTRAINT unique_email IF NOT EXISTS
FOR (u:User) REQUIRE u.email IS UNIQUE;
// Simple index
CREATE INDEX person_name IF NOT EXISTS FOR (p:Person) ON (p.name);List:
SHOW CONSTRAINTS; SHOW INDEXES;9 Batch Inserts with UNWIND
const people=[{name:'Dan',age:33},{name:'Eve',age:28}];
await session.run(
'UNWIND $rows AS row CREATE (p:Person) SET p = row',
{rows: people}
);people=[{"name":"Dan","age":33},{"name":"Eve","age":28}]
session.run(
"UNWIND $rows AS row CREATE (p:Person) SET p = row",
{"rows": people}
)10 Transactions (Python shown)
def add_friend(tx, a, b):
tx.run("MATCH (x:Person {name:$a}), (y:Person {name:$b}) "
"MERGE (x)-[:KNOWS]->(y)", a=a, b=b)
with driver.session() as s:
s.write_transaction(add_friend, "Alice", "Carol")Node.js equivalent: await session.executeWrite(tx=>tx.run(...))
11 Profile & Tune
EXPLAIN <query>→ show plan without running.PROFILE <query>→ run & return db‑hits, rows, time.- Look for NodeByLabelScan (slow). Add indexes until you see NodeIndexSeek / NodeIndexScan.
12 Close & Cleanup
Always:
await session.close();
await driver.close();session.close()
driver.close()Mini‑Glossary
| Term | Meaning |
|---|---|
| Node | Entity / record (row) |
| Label | Node tag (table name) |
| Relationship | Typed, directed edge |
| Property | Key–value on node/rel |
| Path | Ordered chain of nodes & relationships |
| Cypher | Query language |
One‑Minute Warm‑up Script (Node.js)
import neo4j from 'neo4j-driver';
const d = neo4j.driver('neo4j://localhost', neo4j.auth.basic('neo4j','pass'));
const s = d.session();
await s.run("CREATE (:Person {name:'Neo'})");
const res = await s.run("MATCH (n:Person) RETURN n.name AS name");
console.log(res.records[0].get('name')); // -> Neo
await s.close();
await d.close();Print this page, stick it on your monitor, and graph fearlessly. 🚀
comment