Skip to main content
Play · Sandbox

Graph Playground

Graphs reward experimentation more than most models, because the interesting questions are the ones you did not think to ask when you designed the schema. Start with a hosted instance that already has data in it - modelling your own comes later, and is easier once you have seen a few good ones.

What you practise here

  • Cypher: MATCH, WHERE, variable-length paths, aggregation
  • Modelling relationships as first-class rather than as join tables
  • Traversals, shortest paths and centrality
  • Driving a graph database from Python

Notebooks & hosted labs

Environments that run in a browser tab or in one command on your own machine. Nothing here needs a licence.

Starter code samples

Short enough to read in one go and to paste into a cell. Change them until they break — that is the exercise.

Ask this platform's own graph a question

cypher

The labels below are the ones Cyber Scallywags actually runs on: User, Community and Content, joined by MEMBER_OF and AUTHORED.

// Tutorials written by people in the same club as you.
MATCH (you:User {email: $email})-[:MEMBER_OF]->(club:Community)
MATCH (club)<-[:MEMBER_OF]-(peer:User)-[:AUTHORED]->(t:Content)
WHERE peer <> you AND t.status = 'PUBLISHED'
RETURN club.name AS club,
       peer.display_name AS author,
       collect(t.title)[..3] AS tutorials
ORDER BY club, author

Variable-length paths are the whole point

cypher

The query a relational schema makes you write a recursive CTE for. Cap the depth: unbounded traversals on a dense graph do not come back.

// Who is two to four hops away, and how did we get there?
MATCH path = (you:User {email: $email})-[:MEMBER_OF*2..4]-(other:User)
WHERE other <> you
RETURN other.display_name AS person,
       length(path) AS hops,
       [n IN nodes(path) WHERE n:Community | n.name] AS via
ORDER BY hops
LIMIT 10

Driving it from Python

python

Parameters, not string formatting - $slug is sent alongside the query, so a value can never be read as Cypher.

from neo4j import AsyncGraphDatabase

driver = AsyncGraphDatabase.driver(
    "neo4j://localhost:7687", auth=("neo4j", "password")
)

async with driver.session() as session:
    result = await session.run(
        """
        MATCH (u:User)-[:MEMBER_OF]->(c:Community {slug: $slug})
        RETURN u.display_name AS name
        ORDER BY name LIMIT 10
        """,
        slug="graphinista",
    )
    async for record in result:
        print(record["name"])

await driver.close()

Free practice grounds

Places to keep going once the samples run. Every one is usable without paying; where an account is needed we have said so.

Reference & documentation

What to read when the sandbox stops answering the question.

Keep going with the community

The links above belong to the wider web. These ones belong to us — written, reviewed and taught by members.

Other sandboxes