Skip to content
SP StackPractices
intermediate By StackPractices

Graph Databases — Neo4j and Property Graph Modeling

A practical guide to graph databases: property graph model, Cypher query language, modeling patterns, and when to choose Neo4j over relational databases.

Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.

Overview

Graph databases store data as nodes (entities) and edges (relationships), making them ideal for problems where connections between data points are as important as the data itself. Social networks, fraud detection, recommendation engines, and knowledge graphs all benefit from native graph storage. Neo4j, the leading property graph database, uses the Cypher query language and achieves constant-time traversals regardless of graph depth — something relational databases struggle with due to join explosion.

When to Use

  • Relationships are the primary query concern, not just attributes
  • You need to traverse many hops efficiently (friend-of-friend, supply chain)
  • Schema is fluid and new relationship types emerge frequently
  • Pathfinding, centrality, or community detection is required
  • A relational model would require excessive self-joins or junction tables

Property Graph Model

ElementDescriptionExample
NodeEntity with labels and properties(p:Person {name: "Alice", age: 30})
RelationshipTyped, directed connection with properties[:FRIENDS {since: 2020}]
LabelCategorizes nodes:Person, :Product, :Order
PropertyKey-value attribute on node or relationshipname, since, amount

Cypher Basics

-- Create nodes and a relationship
CREATE (alice:Person {name: 'Alice', city: 'NYC'})
CREATE (bob:Person {name: 'Bob', city: 'LA'})
CREATE (alice)-[:FRIENDS {since: 2020}]->(bob);

-- Find friends of friends
MATCH (alice:Person {name: 'Alice'})-[:FRIENDS*2]->(fof:Person)
WHERE fof <> alice
RETURN DISTINCT fof.name;

-- Shortest path between two people
MATCH p=shortestPath(
    (a:Person {name: 'Alice'})-[:FRIENDS|COLLEAGUE*]-(b:Person {name: 'Zoe'})
)
RETURN p;

Real-World Patterns

Recommendation Engine

-- Collaborative filtering: people who bought X also bought Y
MATCH (u:User)-[:BOUGHT]->(p:Product {name: 'Widget'})
MATCH (u)-[:BOUGHT]->(other:Product)
WHERE other <> p
RETURN other.name, count(*) as popularity
ORDER BY popularity DESC
LIMIT 5;

Fraud Detection

-- Detect circular money transfers ( layering )
MATCH path=(a:Account)-[:TRANSFERRED_TO*3..5]->(a)
RETURN path;

Access Control

-- Check if user has access through group membership
MATCH (u:User {id: 123})-[:MEMBER_OF*0..]->(g:Group)-[:CAN_ACCESS]->(r:Resource {id: 'doc-1'})
RETURN count(r) > 0 as has_access;

Graph vs Relational

Query typeRelationalGraph
1-hop lookupJOINDirect edge traversal
3+ hop traversalMultiple JOINs, slowConstant-time per hop
Path findingRecursive CTE, complexNative shortestPath
Schema evolutionALTER TABLEAdd labels/relationships dynamically

Common Mistakes

  • Modeling everything as a graph — simple tabular data is often better in a relational database
  • Ignoring direction — relationships have direction in property graphs; design queries accordingly
  • Missing indexes — create indexes on properties you search frequently (e.g., CREATE INDEX ON :Person(email))
  • Deep traversals without limits — unconstrained variable-length paths can consume excessive resources
  • Storing large properties on relationships — keep relationship properties small; use nodes for rich data

FAQ

When should I NOT use a graph database? When relationships are shallow (1-2 hops), data is highly structured and static, or you need strong ACID transactions across the entire graph. Relational databases handle these well.

Can I run graph queries on PostgreSQL? Yes, with extensions like Apache AGE or recursive CTEs, but performance degrades with graph depth. For deep traversals, a native graph database is better.

What is RDF vs property graph? RDF is a W3C standard for semantic graphs (triples). Property graphs (Neo4j, Amazon Neptune) are more developer-friendly with labeled nodes, typed relationships, and properties on both.