# Neo4j Patterns

> When to activate: Neo4j, Cypher, graph database, nodes, relationships, APOC, graph algorithms, knowledge graph

- Skill: `mattakushi432/neo4j-patterns` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mattakushi432/neo4j-patterns`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mattakushi432/neo4j-patterns/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Mattakushi432 (https://skillmd.com/u/mattakushi432)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/mattakushi432/neo4j-patterns

---

# Neo4j Graph Patterns

## Cypher Queries

```cypher
// 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

```cypher
// 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

```cypher
// 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

```cypher
// 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

```python
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

```cypher
// 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;
```

