npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nodedb-json

v1.3.0

Published

A lightweight JSON-based database for Node.js with TypeScript support, indexing, and complex query capabilities

Readme

nodedb-json

nodedb-json is a lightweight JSON file database tool designed for Node.js. It provides an easy-to-use API for setting, reading, querying, updating, and deleting data stored in JSON files. Supports both CommonJS and ES6 module syntax, as well as TypeScript.

Features

  • Simple and Intuitive: Easy-to-use API for seamless interaction with JSON files.
  • Persistent Storage: Data is stored persistently in JSON files, perfect for Node.js.
  • Flexible Querying: Supports querying and filtering of collections.
  • Array Operations: Provides robust methods for manipulating arrays, including adding, removing, and updating elements.
  • Lightweight: Minimal dependencies, ensuring fast performance.
  • TypeScript Support: Full TypeScript support with type definitions.
  • Batch Operations: Support for executing multiple operations in batch.
  • Indexing: Supports creating indexes on array fields for faster lookups.

Installation

npm install nodedb-json

Usage

CommonJS

const NodedbJson = require('nodedb-json');
const db = new NodedbJson('path/to/db.json');

db.set('name', 'John Doe');
console.log(db.get('name')); // Outputs: John Doe

ES6

import NodedbJson from 'nodedb-json';
const db = new NodedbJson('path/to/db.json');

db.set('name', 'John Doe');
console.log(db.get('name')); // Outputs: John Doe

TypeScript

import NodedbJson from 'nodedb-json';

// Define your data types
interface User {
  id: number;
  name: string;
  age: number;
}

// Create database with options
const db = new NodedbJson<User>('path/to/db.json', {
  autoSave: true,
  createIfNotExists: true,
  defaultValue: { users: [] }
});

// Type-safe operations
db.push('users', { id: 1, name: 'John', age: 30 });
const user = db.find<User>('users', user => user.id === 1);

Basic Operations

Set

db.set("key", "value");

Get

const value = db.get("key");

Update

// Update an object
db.update("key", { newField: "newValue" });

// Update an array item
db.update("arrayKey", (item) => item.id === 1, { name: "Updated Name" });

Delete

// Delete a key
db.delete("key");

// Delete array items using a predicate
db.delete("arrayKey", (item) => item.id === 1);

// Batch delete array items by specified field
db.delete("arrayKey", [1, 3]); // Deletes items with id 1 and 3
db.delete("arrayKey", ["Alice", "Charlie"], "name"); // Deletes items with name 'Alice' and 'Charlie'

Push

db.push("users", { name: "Bob", age: 30 }).push("users", { name: "Charlie", age: 35 });
db.push("users", [
    { name: "Bob", age: 30 },
    { name: "Charlie", age: 35 },
]);

Advanced Operations

Find

const item = db.find("arrayKey", (item) => item.id === 2);

Filter

const items = db.filter("arrayKey", (item) => item.isActive);

Batch Operations

db.batch([
  { method: "set", args: ["config.theme", "dark"] },
  { method: "set", args: ["config.language", "zh-CN"] },
  { method: "push", args: ["logs", { time: new Date().toISOString(), action: "配置更新" }] }
]);

Manual Save

// Configure auto-save
const db = new NodedbJson('path/to/db.json', { autoSave: false });

// Make changes
db.set("key1", "value1");
db.set("key2", "value2");

// Manually save when ready
db.save();

Indexing

Indexing can significantly improve lookup performance for large datasets:

// Create a unique index on the 'id' field
db.createIndex("users", { field: "id", type: "unique" });

// Create a multi-value index on the 'age' field
db.createIndex("users", { field: "age", type: "multi" });

// Find using index
const user = db.findByField("users", "id", 1);

// Filter using index
const adults = db.filterByField("users", "age", [30, 40, 50]);

// Drop an index when no longer needed
db.dropIndex("users", "age");

Changelog

[1.3.0] - 2025-06-03

  • Major Feature Update: Complex Query Support
    • Added query() method with comprehensive query operations
    • Support for multi-field sorting
    • Support for pagination queries
    • Support for aggregation operations: count, sum, avg, min, max, group
    • Support for field selection/projection
    • Added convenient query methods: orderBy(), paginate(), count(), aggregate(), distinct()
    • Intelligent index utilization with automatic query optimization
    • Detailed query statistics (execution time, index usage, etc.)
  • Performance Optimizations
    • Query operations with index acceleration support
    • Lazy evaluation for optimized large dataset processing
    • Execution time monitoring and performance metrics
  • Developer Experience Improvements
    • Complete TypeScript type support
    • Rich documentation and examples
    • Added npm run example:query demonstration script

[1.2.0] - 2025-05-26

  • Added indexing support for faster lookups
  • Added findByField and filterByField methods for index-based queries
  • Performance improvements for large datasets

[1.1.0] - 2025-05-13

  • Added TypeScript support with type definitions
  • Added batch operations
  • Added configuration options
  • Added manual save functionality
  • Improved error handling

[1.0.0] - 2024-05-27

  • Major version update.
  • Added support for ES6 module syntax.
  • Enhanced delete method to support batch deletion by specifying a field.
  • Added JSDoc comments for all methods.

[0.1.4] - 2024-05-20

  • Initial release with basic CRUD operations.
  • Support for array operations with push, find, and filter.

API Documentation

Constructor Options

interface DbOptions {
  autoSave?: boolean;        // Auto save after each operation (default: true)
  createIfNotExists?: boolean; // Create file if it doesn't exist (default: true)
  defaultValue?: Record<string, any>; // Default value for new database
  enableIndexing?: boolean;   // Enable indexing functionality (default: true)
  autoIndex?: boolean;        // Auto rebuild indexes on start (default: true)
}

Basic Methods

set(key, value)

Sets a value in the JSON data.

  • Parameters:
    • key (string): The key to set.
    • value (any): The value to set.
  • Returns: NodedbJson - The instance of the database for chaining.

get(key)

Gets a value from the JSON data.

  • Parameters:
    • key (string): The key to get.
  • Returns: any - The value.

has(key)

Checks if a key exists in the JSON data.

  • Parameters:
    • key (string): The key to check.
  • Returns: boolean - True if the key exists, otherwise false.

update(key, predicateOrUpdater, updater)

Updates a value in the JSON data.

  • Parameters:
    • key (string): The key to update.
    • predicateOrUpdater (function|object): The predicate function or updater object.
    • updater (object) [optional]: The updater object if a predicate function is provided.
  • Returns: NodedbJson - The instance of the database for chaining.

delete(key, predicateOrKeys, field)

Deletes a value from the JSON data.

  • Parameters:
    • key (string): The key to delete.
    • predicateOrKeys (function|string[]) [optional]: The predicate function or array of keys to delete.
    • field (string) [optional]: The field to match for array deletion. Default is 'id'.
  • Returns: NodedbJson - The instance of the database for chaining.

find(key, predicate)

Finds a value in the JSON data.

  • Parameters:
    • key (string): The key to find.
    • predicate (function): The predicate function to match.
  • Returns: any - The found value.

filter(key, predicate)

Filters values in the JSON data.

  • Parameters:
    • key (string): The key to filter.
    • predicate (function): The predicate function to match.
  • Returns: any[] - The filtered values.

push(key, value)

Pushes a value into an array in the JSON data.

  • Parameters:
    • key (string): The key to push to.
    • value (any|any[]): The value or values to push.
  • Returns: NodedbJson - The instance of the database for chaining.

Advanced Methods

batch(operations)

Executes multiple operations in batch.

  • Parameters:
    • operations (Array<{method: string, args: any[]}>): Array of operations to execute.
  • Returns: NodedbJson - The instance of the database for chaining.

save()

Manually save changes to file.

  • Returns: NodedbJson - The instance of the database for chaining.

Indexing Methods

createIndex(key, indexDefinition)

Creates an index on a field for faster lookups.

  • Parameters:
    • key (string): The collection path to index.
    • indexDefinition (IndexDefinition): The index definition with field and type.
  • Returns: NodedbJson - The instance of the database for chaining.

findByField(key, field, value)

Finds a value by field using an index if available.

  • Parameters:
    • key (string): The key to find.
    • field (string): The field to match.
    • value (any): The value to match.
  • Returns: any - The found value.

filterByField(key, field, values)

Filters values by field and possible values using an index if available.

  • Parameters:
    • key (string): The key to filter.
    • field (string): The field to match.
    • values (any[]): The values to match.
  • Returns: any[] - The filtered values.

dropIndex(key, field)

Removes an index.

  • Parameters:
    • key (string): The collection path.
    • field (string): The field name.
  • Returns: NodedbJson - The instance of the database for chaining.

getIndexes()

Gets all index definitions.

  • Returns: Record<string, Record<string, IndexDefinition>> - The index definitions.

Complex Query Operations

NodeDB-JSON supports powerful complex query operations including sorting, pagination, aggregation, and more. All query operations can leverage indexes for optimal performance.

Core Query Method

query(key, options)

Executes a complex query with multiple options.

  • Parameters:
    • key (string): The collection path to query.
    • options (QueryOptions): Query configuration object.
  • Returns: QueryResult - Comprehensive query results with data, pagination, aggregations, and statistics.

Query Options

interface QueryOptions<T = any> {
  where?: PredicateFunction<T> | Record<string, any>;  // Filter conditions
  sort?: SortOption | SortOption[];                    // Sorting options
  pagination?: PaginationOption;                       // Pagination settings
  aggregation?: AggregationOption[];                   // Aggregation operations
  select?: string[];                                   // Field selection (projection)
  limit?: number;                                      // Limit results
  skip?: number;                                       // Skip records
}

Basic Examples

Filtering and Sorting

// Find tech department employees, sorted by salary (descending)
const result = db.query('users', {
  where: { department: '技术部' },
  sort: { field: 'salary', direction: 'desc' }
});

console.log('Found:', result.data.length, 'records');
console.log('Execution time:', result.stats.executionTime, 'ms');
console.log('Used index:', result.stats.usedIndex);

Multi-field Sorting

// Sort by department (ascending), then by salary (descending)
const result = db.query('users', {
  sort: [
    { field: 'department', direction: 'asc' },
    { field: 'salary', direction: 'desc' }
  ]
});

Pagination

// Get page 2 with 5 records per page
const result = db.query('users', {
  sort: { field: 'salary', direction: 'desc' },
  pagination: { page: 2, pageSize: 5 }
});

console.log('Current page:', result.pagination.currentPage);
console.log('Total pages:', result.pagination.totalPages);
console.log('Has next page:', result.pagination.hasNext);

Field Selection (Projection)

// Select only specific fields
const result = db.query('users', {
  where: { department: '技术部' },
  select: ['name', 'salary', 'age'],
  sort: { field: 'salary', direction: 'desc' }
});

Aggregation Operations

Basic Aggregations

// Get various statistics
const result = db.query('users', {
  aggregation: [
    { type: 'count' },                    // Count records
    { type: 'avg', field: 'salary' },     // Average salary
    { type: 'sum', field: 'salary' },     // Total salary
    { type: 'min', field: 'salary' },     // Minimum salary
    { type: 'max', field: 'salary' },     // Maximum salary
  ]
});

result.aggregations?.forEach(agg => {
  console.log(`${agg.type}:`, agg.value);
});

Group By

// Group by department
const result = db.query('users', {
  aggregation: [
    { type: 'group', groupBy: 'department' }
  ]
});

const groups = result.aggregations?.[0]?.value as Record<string, any[]>;
Object.entries(groups).forEach(([dept, users]) => {
  console.log(`${dept}: ${users.length} employees`);
});

Complex Query Example

// Complex query combining multiple features
const result = db.query('users', {
  where: user => user.department === '技术部' && user.salary > 12000,
  sort: { field: 'age', direction: 'asc' },
  pagination: { page: 1, pageSize: 10 },
  select: ['name', 'age', 'salary'],
  aggregation: [
    { type: 'count' },
    { type: 'avg', field: 'salary' }
  ]
});

console.log('Results:', result.data);
console.log('Total matching records:', result.aggregations?.[0]?.value);
console.log('Average salary:', result.aggregations?.[1]?.value);

Convenience Methods

For common operations, convenience methods are available:

orderBy(key, sort, limit?)

Quick sorting with optional limit.

// Get top 5 highest paid employees
const topEarners = db.orderBy('users', 
  { field: 'salary', direction: 'desc' }, 
  5
);

paginate(key, page, pageSize, where?)

Quick pagination with optional filtering.

// Get first page of sales department
const salesPage = db.paginate('users', 1, 10, { department: '销售部' });

count(key, where?)

Count records with optional filtering.

// Count tech department employees
const techCount = db.count('users', { department: '技术部' });

aggregate(key, aggregations, where?)

Execute aggregations with optional filtering.

// Get tech department salary statistics
const techStats = db.aggregate('users', [
  { type: 'count' },
  { type: 'avg', field: 'salary' },
  { type: 'max', field: 'salary' }
], { department: '技术部' });

distinct(key, field)

Get unique values for a field.

// Get all unique departments
const departments = db.distinct('users', 'department');
console.log('Departments:', departments);

Performance Features

  • Index-aware filtering: Automatically uses indexes when available for object-based where conditions
  • Optimized sorting: Leverages lodash's efficient orderBy implementation
  • Lazy evaluation: Pagination and limits are applied efficiently
  • Execution statistics: Get detailed performance metrics for each query

Query Result Structure

interface QueryResult<T> {
  data: T[];                           // Query results
  pagination?: PaginationInfo;         // Pagination details (if used)
  aggregations?: AggregationResult[];  // Aggregation results (if used)
  stats: {
    totalRecords: number;              // Total records before filtering
    filteredRecords: number;           // Records after filtering
    executionTime: number;             // Query execution time (ms)
    usedIndex: boolean;                // Whether indexes were used
  };
}

License

MIT

Contact

For any questions or feedback, please contact me at [email protected].

For issues and support, visit the GitHub Issues page.