skills/role-expert-data_ontologist/SKILL.md
Polyglot persistence: when to use relational, graph, or document databases; integration patterns.
npx skillsauth add jasonwarrenuk/goblin-mode Data OntologistInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Architectural guidance for using multiple database technologies together, with emphasis on PostgreSQL/Supabase (relational), Neo4j (graph), and MongoDB (document). Demonstrates when to use each database type and how to integrate them effectively.
Use this skill when:
Start with the graph. Optimise from there.
Most real-world domains are fundamentally about relationships. The graph is the truest representation of how entities connect. Start by thinking in nodes and edges — then decide where to persist based on access patterns and consistency needs.
Right database for right data concern
Don't force all data into one database type. Use:
Before choosing databases, model the domain as a graph:
// Step 1-3: Model the domain as a graph first
(:User)-[:MEMBER_OF {role: 'admin', since: date}]->(:Organisation)
(:User)-[:ENROLLED_IN {status: 'active'}]->(:Course)
(:Course)-[:REQUIRES]->(:Course)
(:User)-[:COMPLETED {score: 0.85}]->(:Module)
(:Module)-[:BELONGS_TO]->(:Course)
Then decide:
Transactional Data:
Structured Records:
Examples:
-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Orders table
CREATE TABLE orders (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
total DECIMAL(10,2),
status TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
Highly Connected Data:
Reason: Joins become expensive, recursive queries complex.
Rapidly Evolving Schemas:
Reason: Migrations expensive, rigid structure.
Relationships as Primary Concern:
Variable-Depth Traversals:
Examples:
// Social connections
(:User)-[:FOLLOWS]->(:User)
(:User)-[:BLOCKED]->(:User)
// Learning paths
(:Course)-[:REQUIRES]->(:Course)
(:User)-[:COMPLETED]->(:Course)
// Organizational structure
(:Person)-[:REPORTS_TO]->(:Person)
(:Person)-[:MEMBER_OF]->(:Team)
Simple Lookups:
Reason: Relational databases excel at indexed lookups.
Large Aggregations:
Reason: SQL aggregations and window functions more powerful.
Semi-Structured Data:
Nested/Embedded Data:
Flexible Schemas:
Examples:
// Blog post with embedded comments
{
_id: ObjectId("..."),
title: "Getting Started with SvelteKit",
slug: "getting-started-sveltekit",
author: { id: "user-123", name: "Alice" },
content: "...",
tags: ["svelte", "javascript", "tutorial"],
comments: [
{ id: "comment-1", userId: "user-456", text: "Great article!", createdAt: ISODate("2024-01-15") }
],
metadata: { views: 1250, readingTime: "5 min" },
publishedAt: ISODate("2024-01-10")
}
// Product with varying attributes
{
_id: ObjectId("..."),
name: "Laptop",
category: "electronics",
price: 999.99,
specs: { cpu: "Intel i7", ram: "16GB", storage: "512GB SSD", screen: "15.6 inch" }
}
// Different product type, different fields
{
_id: ObjectId("..."),
name: "T-Shirt",
category: "clothing",
price: 29.99,
sizes: ["S", "M", "L", "XL"],
colors: ["black", "white", "blue"],
material: "100% cotton"
}
Complex Transactions:
Reason: Relational databases better at multi-document transactions.
Relationship-Heavy Data:
Reason: Graph databases handle this natively.
Highly Normalized Data:
Reason: Relational databases enforce this better.
RELATIONSHIPS → Neo4j (Graph) — social connections, recommendations, dependency trees, path finding
STRUCTURED ENTITIES → PostgreSQL (Relational) — user accounts, financial transactions, inventory, orders
DOCUMENTS/CONTENT → MongoDB (Document) — blog posts, product catalogs, CMS content, API data storage
VERY STABLE → PostgreSQL — well-defined entities, clear field types, rare schema changes, strong typing needed
EVOLVING → MongoDB — prototyping phase, frequently adding fields, different record structures, flexible modeling
SCHEMA-OPTIONAL → Neo4j — relationships more important than structure, dynamic properties, graph structure evolves
BY KEY/ID → PostgreSQL or MongoDB — user by email, product by SKU, order by ID
BY TRAVERSAL → Neo4j — friends of friends, shortest path, recommendations
BY CONTENT/QUERY → MongoDB — full-text search, filtering nested documents, flexible queries on varying fields
ABSOLUTE → PostgreSQL — financial transactions, ACID guarantees, multi-step operations
EVENTUAL OKAY → MongoDB or Neo4j — content updates, social interactions, non-critical data
YES → MongoDB — posts with comments, orders with line items, documents with metadata
NO → PostgreSQL — flat entities, many-to-many relationships, normalized structure
Worked examples and mechanical detail, loaded only when needed:
Architecture is successful when:
tools
{{ 𝚫𝚫𝚫 }} Rebuild roadmap-system.zip, the distributable snapshot of the roadmap tooling (scripts, HTML template, conventions reference, and every roadmap-touching skill, including this one).
tools
--- name: "Suggest: Task" description: "{{ 𝚫𝚫𝚫 }} Suggest the next logical task — grounded in the roadmap's pre-vetted ready-set when one exists, codebase analysis otherwise" when_to_use: "When you don't know what to work on next and want a grounded recommendation rather than picking arbitrarily." model: haiku effort: low disable-model-invocation: true allowed-tools: ["Read", "Glob", "Grep", "Bash(python3:*)", "Bash(npm:*)", "Bash(bun:*)", "Bash(pnpm:*)", "Bash(deno:*)"] argument-hint: [named
development
{{ 𝛀𝛀𝛀 }} Convert an old simple-style roadmap (single Markdown, four statuses, <a name> anchors, roadmaps.json pointer registry) into the rich phase-array format (roadmaps.json source of truth + PHASE task list + prose overview).
data-ai
{{ ƔƔƔ }} Create a pull request to main — wordy or shiny (with screenshots), ready-for-review or draft