JSPM

tiny-graph-db

1.0.2
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 20
  • Score
    100M100P100Q46357F
  • License MIT

A tiny, no-external-dependency, disk-based graph database for Node.js with rich set of operations.

Package Exports

  • tiny-graph-db
  • tiny-graph-db/src/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (tiny-graph-db) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

TinyGraphDB

A tiny, no-external-dependencies, disk-based graph database for Node.js with rich set of operations.

  • Persist simple node-&-edge graphs in a JSON file, and query, traverse or mutate them entirely in JavaScript.
  • TinyGraphDB is a great fit for building lightweight, GraphRAG systems β€” where LLMs retrieve knowledge via structured traversals instead of just flat vector search.
  • Pretty fast too. See Performance Benchmarks section.

Table of Contents


Features

  • βœ… Persistent storage
    Automatically saves all nodes & relations to a JSON file on each change.
  • πŸ” Searchable
    Find nodes or edges by name, metadata, IDs or via complex metadata filters.
  • πŸ”„ Traversals
    Breadth-first-style traversals from any node or relation, with depth, direction and name filters.
  • πŸ”§ CRUD + Batch Ops
    Create, read, update or delete single or multiple nodes/relations by search criteria.
  • πŸ“ˆ Statistics
    Get nodeCount, relationCount and avgDegree.
  • πŸ”„ Import/Export
    Dump your graph into JSON, or load an existing JSON graph.

Installation

npm install tiny-graph-db

Quick Start

const TinyGraphDB = require('tiny-graph-db');
const db = new TinyGraphDB();

// Adding some sample data
const node1 = db.addNode('Document1', { type: 'document', content: 'AI research paper' });
const node2 = db.addNode('Concept1', { type: 'concept', domain: 'AI' });
const node3 = db.addNode('Author1', { type: 'person', name: 'John Doe' });

const rel1 = db.addRelation('contains', node1.id, node2.id, { confidence: 0.9 });
const rel2 = db.addRelation('authored_by', node1.id, node3.id, { confidence: 1.0 });

// Search examples
console.log('Search: nodes with type "concept":', db.searchNodes({ metadata: { type: 'concept' } }));
console.log('Search: relations with confidence > 0.8:', db.searchRelations({ metadata: { confidence: { gt: 0.8 } } }));

// Traversal examples
console.log('Traverse: from node1 (depth 2):', db.traverseFromNode(node1.id, { maxDepth: 2, directions: ['outgoing'] }));
console.log('Traverse: from metadata {type: "document"}:', db.traverseFromMetadata({ type: 'document' }, 1));

// Update example
db.updateNode(node1.id, { name: 'Updated Document', metadata: { updated: true } });

console.log('Graph stats:', db.getStats());

API

Constructor

new TinyGraphDB(filePath?: string)
  • filePath: path to JSON file for persistence (default: ./graph_data.json).

Node Operations

Method Description Returns
addNode(name: string, metadata = {}, flush = true) Creates a node with given name & metadata Node object
getNode(nodeId: string) Fetches a node by its ID Node or undefined
getAllNodes() Returns all nodes Node[]
updateNode(nodeId: string, updates) Update name and/or metadata on a node Updated Node
deleteNode(nodeId: string) Deletes a node and all its connected relations Deleted Node
deleteBySearch('node', conditions) Deletes all nodes matching conditions Node[]

Relation Operations

Method Description Returns
addRelation(name, fromNodeId, toNodeId, metadata = {}, flush = true) Creates an edge between two existing nodes Relation
getRelation(relationId: string) Fetches a relation by ID Relation or undefined
getAllRelations() Returns all relations Relation[]
updateRelation(relationId, updates) Update name and/or metadata on a relation Updated Relation
deleteRelation(relationId: string) Deletes a single relation Deleted Relation
deleteBySearch('relation', conditions) Deletes all relations matching conditions Relation[]

Graph Traversal

traverseFromNode(startNodeId, options?)
traverseFromRelation(startRelationId, maxDepth?)
traverseFromMetadata(metadataConditions, maxDepth?)
  • options for traverseFromNode:

    • maxDepth: number (default: ∞)
    • directions: ['outgoing','incoming']
    • relationName?: filter by relation name
  • Returns: an array of [ fromNode, relation, toNode ] tuples.


searchNodes(conditions: SearchConditions): Node[]
searchRelations(conditions: SearchConditions): Relation[]
  • conditions:

    • name: string | RegExp | { contains: string }

    • id, fromNodeId, toNodeId

    • metadata: { [key]: valueOrFilter }

      • supports { eq, ne, gt, gte, lt, lte, contains, startsWith, endsWith, in }

Examples

const TinyGraphDB = require('tiny-graph-db');
const db = new TinyGraphDB('./example_graph.json');

// β€”β€”β€” Create sample nodes β€”β€”β€”
const book1    = db.addNode('Dune',        { genre: 'sci-fi',   pages: 412,  published: 1965 });
const book2    = db.addNode('Foundation',  { genre: 'sci-fi',   pages: 255,  published: 1951 });
const book3    = db.addNode('Hamlet',      { genre: 'drama',    pages: 160,  published: 1603 });
const author1  = db.addNode('Frank Herbert', { nationality: 'US',  awards: 2 });
const author2  = db.addNode('Isaac Asimov',  { nationality: 'US',  awards: 5 });
const author3  = db.addNode('William Shakespeare', { nationality: 'UK', awards: 0 });

// β€”β€”β€” Create sample relations β€”β€”β€”
const rel1 = db.addRelation('wrote', book1.id,   author1.id, { role: 'author'   });
const rel2 = db.addRelation('wrote', book2.id,   author2.id, { role: 'author'   });
const rel3 = db.addRelation('wrote', book3.id,   author3.id, { role: 'playwright' });
const rel4 = db.addRelation('influenced', author2.id, author1.id, { year: 1960 });
1. Search nodes by exact name
// Find the node whose name is exactly "Dune":
const result = db.searchNodes({ name: 'Dune' });
console.log(result);
// β†’ [ { id: '…', name: 'Dune', metadata: { genre: 'sci-fi', … } } ]
2. Search nodes by name contains (case-insensitive)
// Find all nodes whose name contains "isaac" (will match "Isaac Asimov"):
const result = db.searchNodes({ name: { contains: 'isaac' } });
console.log(result.map(n => n.name));
// β†’ [ 'Isaac Asimov' ]
3. Search nodes by name regex
// Find any book title that starts with 'F' or 'H':
const result = db.searchNodes({ name: /^F|^H/ });
console.log(result.map(n => n.name));
// β†’ [ 'Foundation', 'Hamlet' ]
4. Search nodes by metadata equality and comparison
// All sci-fi books:
const scifi = db.searchNodes({ metadata: { genre: 'sci-fi' } });

// Books published before 1900:
const classics = db.searchNodes({
  metadata: { published: { lt: 1900 } }
});

console.log(scifi.map(n => n.name));     // β†’ [ 'Dune', 'Foundation' ]
console.log(classics.map(n => n.name));  // β†’ [ 'Foundation', 'Hamlet' ]
5. Search nodes by metadata β€œin” list
// Find all authors from US or UK:
const authors = db.searchNodes({
  metadata: { nationality: { in: ['US', 'UK'] } }
});
console.log(authors.map(a => a.name));
// β†’ [ 'Frank Herbert', 'Isaac Asimov', 'William Shakespeare' ]
6. Search relations by relation name and metadata
// All "wrote" relations:
const wroteRels = db.searchRelations({ name: 'wrote' });

// Relations where influence happened after 1950:
const influenceRels = db.searchRelations({
  name: 'influenced',
  metadata: { year: { gt: 1950 } }
});

console.log(wroteRels.length);      // β†’ 3
console.log(influenceRels);         // β†’ [ { id: '…', name: 'influenced', … } ]
7. Combining condition types
// Sci-fi books by authors with >2 awards:
const sciFiBooks = db.searchNodes({
  metadata: { genre: 'sci-fi' }
});
const topAuthors = db.searchNodes({
  metadata: { awards: { gt: 2 } }
});

// Then filter relations:
const result = db
  .getAllRelations()
  .filter(r =>
    r.name === 'wrote'
    && sciFiBooks.some(b => b.id === r.fromNodeId)
    && topAuthors.some(a => a.id === r.toNodeId)
  );
console.log(result);

Import / Export

exportData(): { nodes: Node[]; relations: Relation[] }
importData(data: { nodes; relations })
  • exportData() returns a JSON-serializable object.
  • importData(...) wipes current graph and loads provided data, then persists.

Utility

  • getNeighbors(nodeId) List all adjacent nodes & relation directions.
  • getStats() { nodeCount, relationCount, avgDegree }
  • flushToDisk() Flushes the graph to DB. Everything by-default is always flushed to disk. See flush param in addNode() and addRelation() methods.

Performance Benchmarks

  1. Benchmarking script: node src/benchmark.js 1000 2000 5 or npm run benchmark -- 1000 2000 5
  2. 1000 nodes, ~2000 relations, 5 rounds
  3. Results
Function Time (ms) Ops/sec
getNode() 0.0001 8,473,743
traverseFromNode() 0.0072 138,175
searchNodes() 0.1728 5,787

Contributing

  1. Fork the repo
  2. Create a feature branch git checkout -b feat/my-feature
  3. Commit your changes (git commit -m 'Add awesome feature')
  4. Push (git push origin feat/my-feature)
  5. Open a Pull Request

Please file issues for bugs or feature requests via GitHub Issues.


License

This project is licensed under the MIT License. See LICENSE for details.


Built with β™₯ by freakynit