Neo4j Graph Patterns
Cypher Queries
// Create nodes and relationships
CREATE (alice:User {id: 1, name: 'Alice', email: 'a@b.com'})
CREATE (bob:User {id: 2, name: 'Bob'})
CREATE (alice)-[:FOLLOWS {since: date('2024-01-01')}]->(bob)
// MERGE — create if not exists (upsert)
MERGE (u:User {id: $id})
ON CREATE SET u.name = $name, u.created_at = datetime()
ON MATCH SET u.last_seen = datetime()
// Pattern matching
MATCH (u:User {id: $userId})-[:FOLLOWS]->(followed:User)
RETURN followed.name, followed.email
ORDER BY followed.name LIMIT 20;
// Variable-length paths (friends of friends)
MATCH (me:User {id: $userId})-[:FOLLOWS*1..2]->(recommended:User)
WHERE NOT (me)-[:FOLLOWS]->(recommended) AND me <> recommended
RETURN recommended.name, count(*) AS mutual_connections
ORDER BY mutual_connections DESC LIMIT 10;
// Shortest path
MATCH path = shortestPath(
(a:User {id: $fromId})-[:FOLLOWS*]-(b:User {id: $toId})
)
RETURN [node IN nodes(path) | node.name] AS path_names,
length(path) AS hops;
Graph Modeling
// E-commerce: products, categories, orders
CREATE (p:Product {id: 'p1', name: 'Laptop', price: 999})
CREATE (c:Category {name: 'Electronics'})
CREATE (p)-[:IN_CATEGORY]->(c)
CREATE (o:Order {id: 'o1', total: 999, created: datetime()})
CREATE (u:User {id: 'u1', name: 'Alice'})
CREATE (u)-[:PLACED]->(o)
CREATE (o)-[:CONTAINS {qty: 1, unit_price: 999}]->(p)
// Recommendation: "users who bought X also bought Y"
MATCH (me:User {id: $userId})-[:PLACED]->(:Order)-[:CONTAINS]->(p:Product)
MATCH (other:User)-[:PLACED]->(:Order)-[:CONTAINS]->(p)
MATCH (other)-[:PLACED]->(:Order)-[:CONTAINS]->(rec:Product)
WHERE NOT (me)-[:PLACED]->(:Order)-[:CONTAINS]->(rec)
RETURN rec.name, count(*) AS score
ORDER BY score DESC LIMIT 5;
Indexes and Constraints
// Unique constraint (also creates index)
CREATE CONSTRAINT user_id_unique IF NOT EXISTS
FOR (u:User) REQUIRE u.id IS UNIQUE;
CREATE CONSTRAINT user_email_unique IF NOT EXISTS
FOR (u:User) REQUIRE u.email IS UNIQUE;
// Full-text search index
CREATE FULLTEXT INDEX product_search IF NOT EXISTS
FOR (n:Product) ON EACH [n.name, n.description];
CALL db.index.fulltext.queryNodes('product_search', 'laptop gaming')
YIELD node, score
RETURN node.name, score ORDER BY score DESC LIMIT 10;
// Range index (for inequality queries)
CREATE RANGE INDEX order_date IF NOT EXISTS
FOR (o:Order) ON (o.created);
APOC Procedures
// APOC — essential utility library
// Batch loading from JSON
CALL apoc.load.json('https://example.com/data.json') YIELD value
CALL apoc.create.nodes(['User'], [value]) YIELD node
RETURN node;
// Periodic commit for large imports
CALL apoc.periodic.iterate(
'MATCH (u:User) WHERE u.score IS NULL RETURN u',
'SET u.score = apoc.text.distance(u.name, "default")',
{batchSize: 1000, parallel: false}
);
// Graph refactoring
CALL apoc.refactor.mergeNodes([nodeA, nodeB], {properties: 'combine'});
// JSON path extraction
RETURN apoc.convert.fromJsonMap('{"key":"value"}').key;
Python Driver
from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))
def get_recommendations(user_id):
with driver.session() as session:
result = session.run("""
MATCH (me:User {id: $uid})-[:FOLLOWS]->(:User)-[:FOLLOWS]->(rec:User)
WHERE NOT (me)-[:FOLLOWS]->(rec) AND me.id <> rec.id
RETURN rec.name AS name, count(*) AS score
ORDER BY score DESC LIMIT 10
""", uid=user_id)
return [dict(r) for r in result]
Graph Algorithm Examples
// PageRank (requires GDS plugin)
CALL gds.pageRank.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC LIMIT 10;
// Community detection (Louvain)
CALL gds.louvain.stream('myGraph')
YIELD nodeId, communityId
RETURN communityId, count(*) AS size ORDER BY size DESC;