Neo4j
Port 7687 Graph database — Cypher query language. Bolt only (7474 not exposed).
Connection
NEO4J_URI=bolt://db.bizfylabs.com:7687
NEO4J_USER=myapp_user
NEO4J_PASSWORD=PASSWORD
Setup
npm install neo4j-driver
import neo4j from 'neo4j-driver';
const driver = neo4j.driver(
process.env.NEO4J_URI,
neo4j.auth.basic(process.env.NEO4J_USER, process.env.NEO4J_PASSWORD),
);
const session = driver.session();
// always close: await session.close()
Label Naming
Prefix labels per app: MyApp_User, MyApp_Product, MyApp_Order
Node CRUD
Create
// Single node
await session.run(
'CREATE (u:MyApp_User {id: $id, email: $email, name: $name, createdAt: datetime()}) RETURN u',
{ id: 'u1', email: 'a@b.com', name: 'Alice' }
);
// MERGE (idempotent — create if not exists)
await session.run(
'MERGE (u:MyApp_User {id: $id}) ON CREATE SET u.email = $email, u.name = $name RETURN u',
{ id: 'u1', email: 'a@b.com', name: 'Alice' }
);
Read
// By property
const result = await session.run(
'MATCH (u:MyApp_User {id: $id}) RETURN u',
{ id: 'u1' }
);
const user = result.records[0].get('u').properties;
// List with filter + limit
await session.run(
'MATCH (u:MyApp_User) WHERE u.status = $status RETURN u ORDER BY u.createdAt DESC LIMIT 20',
{ status: 'active' }
);
// Count
await session.run('MATCH (u:MyApp_User) RETURN count(u) AS total');
Update
await session.run(
'MATCH (u:MyApp_User {id: $id}) SET u.name = $name, u.updatedAt = datetime() RETURN u',
{ id: 'u1', name: 'Alice Updated' }
);
Delete
// Delete node + all relationships
await session.run(
'MATCH (u:MyApp_User {id: $id}) DETACH DELETE u',
{ id: 'u1' }
);
Relationship CRUD
Create
await session.run(
`MATCH (a:MyApp_User {id: $from}), (b:MyApp_User {id: $to})
CREATE (a)-[:FOLLOWS {since: date()}]->(b)`,
{ from: 'u1', to: 'u2' }
);
// Product purchase
await session.run(
`MATCH (u:MyApp_User {id: $uid}), (p:MyApp_Product {id: $pid})
CREATE (u)-[:PURCHASED {at: datetime(), qty: $qty}]->(p)`,
{ uid: 'u1', pid: 'p1', qty: 2 }
);
Read
// Friends
await session.run(
'MATCH (u:MyApp_User {id: $id})-[:FOLLOWS]->(f) RETURN f',
{ id: 'u1' }
);
// Friends of friends
await session.run(
`MATCH (u:MyApp_User {id: $id})-[:FOLLOWS]->(f)-[:FOLLOWS]->(fof)
WHERE fof <> u RETURN DISTINCT fof LIMIT 20`,
{ id: 'u1' }
);
// Shortest path
await session.run(
`MATCH path = shortestPath(
(a:MyApp_User {id: $from})-[*]-(b:MyApp_User {id: $to})
) RETURN path`,
{ from: 'u1', to: 'u5' }
);
Update Relationship
await session.run(
`MATCH (a:MyApp_User {id: $from})-[r:FOLLOWS]->(b:MyApp_User {id: $to})
SET r.since = date()`,
{ from: 'u1', to: 'u2' }
);
Delete Relationship
await session.run(
`MATCH (a:MyApp_User {id: $from})-[r:FOLLOWS]->(b:MyApp_User {id: $to})
DELETE r`,
{ from: 'u1', to: 'u2' }
);
Indexes & Constraints
CREATE CONSTRAINT myapp_user_id IF NOT EXISTS
FOR (u:MyApp_User) REQUIRE u.id IS UNIQUE;
CREATE INDEX myapp_user_email IF NOT EXISTS
FOR (u:MyApp_User) ON (u.email);
Python CRUD
with driver.session() as session:
session.run("CREATE (u:MyApp_User {id: $id}) RETURN u", id="u1")
result = session.run("MATCH (u:MyApp_User {id: $id}) RETURN u", id="u1")
session.run("MATCH (u:MyApp_User {id: $id}) SET u.name = $name", id="u1", name="Bob")
session.run("MATCH (u:MyApp_User {id: $id}) DETACH DELETE u", id="u1")
Admin — Create User
Platform admin only.
docker exec -it bizfy-neo4j cypher-shell -u neo4j -p
// Read/write user
CREATE USER myapp_user SET PASSWORD 'strong-random-password' CHANGE NOT REQUIRED;
GRANT ROLE editor TO myapp_user;
// Read-only user
CREATE USER myapp_readonly SET PASSWORD 'strong-random-password' CHANGE NOT REQUIRED;
GRANT ROLE reader TO myapp_readonly;
// List users
SHOW USERS;
// Delete user
DROP USER myapp_user IF EXISTS;
Neo4j Roles
| Role | Access |
|---|---|
reader | Read-only Cypher |
editor | Read + write data |
admin | Full access (do not give to apps) |
Send to Developer
NEO4J_URI=bolt://db.bizfylabs.com:7687
NEO4J_USER=myapp_user
NEO4J_PASSWORD=PASSWORD