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'));
ES6
import NodedbJson from 'nodedb-json';
const db = new NodedbJson('path/to/db.json');
db.set('name', 'John Doe');
console.log(db.get('name'));
TypeScript
import NodedbJson from 'nodedb-json';
interface User {
id: number;
name: string;
age: number;
}
const db = new NodedbJson<User>('path/to/db.json', {
autoSave: true,
createIfNotExists: true,
defaultValue: { users: [] }
});
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
db.update("key", { newField: "newValue" });
db.update("arrayKey", (item) => item.id === 1, { name: "Updated Name" });
Delete
db.delete("key");
db.delete("arrayKey", (item) => item.id === 1);
db.delete("arrayKey", [1, 3]);
db.delete("arrayKey", ["Alice", "Charlie"], "name");
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
const db = new NodedbJson('path/to/db.json', { autoSave: false });
db.set("key1", "value1");
db.set("key2", "value2");
db.save();
Indexing
Indexing can significantly improve lookup performance for large datasets:
db.createIndex("users", { field: "id", type: "unique" });
db.createIndex("users", { field: "age", type: "multi" });
const user = db.findByField("users", "id", 1);
const adults = db.filterByField("users", "age", [30, 40, 50]);
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;
createIfNotExists?: boolean;
defaultValue?: Record<string, any>;
enableIndexing?: boolean;
autoIndex?: boolean;
}
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>;
sort?: SortOption | SortOption[];
pagination?: PaginationOption;
aggregation?: AggregationOption[];
select?: string[];
limit?: number;
skip?: number;
}
Basic Examples
Filtering and Sorting
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
const result = db.query('users', {
sort: [
{ field: 'department', direction: 'asc' },
{ field: 'salary', direction: 'desc' }
]
});
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)
const result = db.query('users', {
where: { department: '技术部' },
select: ['name', 'salary', 'age'],
sort: { field: 'salary', direction: 'desc' }
});
Aggregation Operations
Basic Aggregations
const result = db.query('users', {
aggregation: [
{ type: 'count' },
{ type: 'avg', field: 'salary' },
{ type: 'sum', field: 'salary' },
{ type: 'min', field: 'salary' },
{ type: 'max', field: 'salary' },
]
});
result.aggregations?.forEach(agg => {
console.log(`${agg.type}:`, agg.value);
});
Group By
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
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.
const topEarners = db.orderBy('users',
{ field: 'salary', direction: 'desc' },
5
);
paginate(key, page, pageSize, where?)
Quick pagination with optional filtering.
const salesPage = db.paginate('users', 1, 10, { department: '销售部' });
count(key, where?)
Count records with optional filtering.
const techCount = db.count('users', { department: '技术部' });
aggregate(key, aggregations, where?)
Execute aggregations with optional filtering.
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.
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[];
pagination?: PaginationInfo;
aggregations?: AggregationResult[];
stats: {
totalRecords: number;
filteredRecords: number;
executionTime: number;
usedIndex: boolean;
};
}
License
MIT
Contact
For any questions or feedback, please contact me at douyaj33@gmail.com.
For issues and support, visit the GitHub Issues page.