1.0.7 • Published 6 months ago
@sinkingsheep/jsondb v1.0.7
JsonDB
A powerful, MongoDB-like JSON database for Node.js with TypeScript support. JsonDB provides rich querying capabilities, transactions, indexing, and more, while maintaining data in simple JSON files.
Features
- 💪 Strong TypeScript support
- 🔍 Rich query API (MongoDB-like operators)
- 📑 Multiple collection support
- 🔄 Transaction support with rollback
- 📇 Indexing with unique and sparse options
- 🔗 Collection joins
- ✅ Schema validation
- 💾 Automatic saving
- 🎯 Event system
- ⛓️ Chain syntax for queries
Installation
npm install @sinkingsheep/jsondb
# or
yarn add @sinkingsheep/jsondb
Quick Start
import JsonDB from '@sinkingsheep/jsondb';
interface User {
id?: string;
name: string;
age: number;
email: string;
}
async function main() {
// Initialize database
const db = new JsonDB({
directory: './data',
autoSave: true,
saveInterval: 1000
});
await db.init();
// Insert a document
const user = await db.insert<User>('users', {
name: 'John Doe',
age: 30,
email: 'john@example.com'
});
// Query documents
const users = await db.find('users', {
age: { $gt: 25 }
});
// Close database
await db.close();
}
Database Operations
Initialization
interface DBOptions {
directory: string;
autoSave?: boolean;
saveInterval?: number;
prettyPrint?: boolean;
}
const db = new JsonDB({
directory: './data',
autoSave: true,
saveInterval: 1000,
prettyPrint: true
});
await db.init();
Basic CRUD Operations
Insert
// Single insert
const user = await db.insert<User>('users', {
name: 'John',
age: 30
});
// Bulk insert
const users = await db.insertMany<User>('users', [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 }
]);
Find
// Find all matching documents
const users = await db.find('users', {
age: { $gt: 25 }
});
// Find one document
const user = await db.findOne('users', {
name: 'John'
});
// Chain syntax
const results = await db
.chain('users')
.where({ status: 'active' })
.sort({ age: -1 })
.limit(10)
.find();
Update
// Update multiple documents
const updateCount = await db.update('users',
{ status: 'inactive' },
{ status: 'active' }
);
// Update single document
const updated = await db.updateOne('users',
{ id: 'user123' },
{ status: 'active' }
);
Delete
const deleteCount = await db.delete('users', {
status: 'inactive'
});
Query Operators
Comparison Operators
// Equal to
{ age: { $eq: 30 } }
// Greater than
{ age: { $gt: 25 } }
// Less than or equal to
{ age: { $lte: 40 } }
// In array
{ status: { $in: ['active', 'pending'] } }
// Not in array
{ status: { $nin: ['deleted', 'banned'] } }
Logical Operators
// AND
{
$and: [
{ status: 'active' },
{ age: { $gt: 25 } }
]
}
// OR
{
$or: [
{ status: 'admin' },
{ role: 'moderator' }
]
}
// NOT
{
status: { $not: { $eq: 'inactive' } }
}
Array Operators
// Array contains all elements
{ scores: { $all: [80, 85] } }
// Array size
{ scores: { $size: 3 } }
// Element match
{ scores: { $elemMatch: { $gte: 90 } } }
Indexing
// Create unique index
await db.createIndex('users', 'email', { unique: true });
// Create sparse index
await db.createIndex('users', 'optional_field', { sparse: true });
Transactions
// Begin transaction
const transactionId = await db.beginTransaction();
try {
await db.insert('accounts', { id: '1', balance: 100 });
await db.update('accounts', { id: '1' }, { balance: 50 });
await db.commitTransaction(transactionId);
} catch (error) {
await db.rollbackTransaction(transactionId);
throw error;
}
Joins
const results = await db.findWithJoin('orders',
{ status: 'pending' },
{
joins: [{
collection: 'users',
localField: 'userId',
foreignField: 'id',
as: 'user'
}]
}
);
Schema Validation
const userSchema = defineSchema({
name: 'string',
age: 'number',
email: 'string'
});
const isValid = validateDocument(userSchema, document);
Events
db.on('save', (collectionName) => {
console.log(`Collection ${collectionName} was saved`);
});
db.on('update', (collectionName, document) => {
console.log(`Document updated in ${collectionName}`);
});
db.on('delete', (collectionName, documentId) => {
console.log(`Document ${documentId} deleted from ${collectionName}`);
});
Chain Syntax
JsonDB provides a fluent chain syntax for building queries:
const results = await db
.chain('users')
.where({ status: 'active' })
.sort({ age: -1 })
.skip(10)
.limit(5)
.find();
const user = await db
.chain('users')
.where({ age: { $gt: 30 } })
.findOne();
Performance Considerations
- Collections are loaded lazily on first access
- Each collection is stored in a separate file
- Indexes improve query performance for indexed fields
- Auto-save interval is configurable
- In-memory caching of loaded collections
Error Handling
try {
await db.insert('users', { email: 'duplicate@email.com' });
} catch (error) {
if (error.message.includes('Unique constraint violation')) {
// Handle unique constraint violation
}
throw error;
}
TypeScript Support
JsonDB is written in TypeScript and provides full type support:
interface User {
id?: string;
name: string;
age: number;
email: string;
}
const user = await db.insert<User>('users', {
name: 'John',
age: 30,
email: 'john@example.com'
});
Best Practices
Collection Management
- Use separate collections for different types of data
- Consider collection joins for related data
- Drop unused collections to free up resources
Indexing
- Create indexes for frequently queried fields
- Use sparse indexes for optional fields
- Be mindful of index overhead for write operations
Transactions
- Use transactions for operations that need to be atomic
- Always handle transaction errors and rollbacks
- Keep transactions as short as possible
Performance
- Use specific queries instead of loading all documents
- Implement pagination for large result sets
- Configure auto-save interval based on your needs
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Credits
Created and maintained by sinkingsheep