Modern, feature-rich and secure JSON database module for Node.js.
- π Simple & User-Friendly: Minimalist API for quick start
- πΎ Auto Save: Automatically saves on every operation (configurable)
- π Dot Notation: Easy access to nested objects (
user.settings.theme) - π TypeScript Support: Full TypeScript definitions included
- π― Zero Dependencies: No external dependencies required
- β‘ Lightweight: Minimal file size
- π AES-256 Encryption: Secure your database with password encryption
- π¦ Gzip Compression: Reduce file size with compression
- πΌ Transactions: Begin, commit, and rollback operations
- π Query Builder: SQL-like queries on arrays
- π Collection API: MongoDB-like document collections
- β° TTL Support: Auto-expiring keys
- π Watch/Observe: Listen to data changes
- π‘ Event Emitter: React to database events
- β Schema Validation: Validate data before saving
- πΎ Backup/Restore: Automatic backups with restore capability
- π Plugin System: Extend functionality with plugins
- β‘ Async/Await: Promise-based async operations
- π¦ ESM Support: ES Modules support
npm install datara
or
yarn add datara
const Datara = require('datara'); // Create a database const db = new Datara('./mydb.json'); // Save data db.set('name', 'Datara'); db.set('version', '2.0.0'); // Read data console.log(db.get('name')); // 'Datara' // Nested objects db.set('user.name', 'devraikou'); db.set('user.settings.theme', 'dark'); console.log(db.get('user')); // { name: 'devraikou', settings: { theme: 'dark' }} // Clean up when done db.close();
const Datara = require('datara'); // Basic usage const db = new Datara('./database.json'); // With options const db = new Datara('./database.json', { autoSave: true, // Auto-save on every operation (default: true) pretty: true, // Pretty print JSON (default: true) indentSize: 2, // Indentation size (default: 2) encryption: 'secret', // Encryption password (default: null) compression: true, // Enable gzip compression (default: false) backupInterval: 3600000, // Auto-backup interval in ms (default: null) maxBackups: 5, // Max backup files to keep (default: 5) timestamps: true, // Add timestamps to objects (default: false) schema: { // Schema validation rules (default: null) username: { type: 'string', required: true } } });
Save data to the database.
db.set('username', 'devraikou'); db.set('score', 100); db.set('active', true); // Nested objects with dot notation db.set('user.profile.name', 'Ali'); db.set('settings.theme.color', 'dark');
Read data from the database.
const username = db.get('username'); // 'devraikou' const score = db.get('score'); // 100 // With default value const lang = db.get('language', 'en'); // 'en' (if not exists) // Get all data const allData = db.get(); // Entire database
Check if a key exists.
db.has('username'); // true db.has('nonexistent'); // false
Delete a key.
db.delete('username'); // true db.delete('nonexistent'); // false
Update a value using a callback function.
db.set('counter', 10); db.update('counter', val => val * 2); // 20
Rename a key.
db.set('oldName', 'value'); db.rename('oldName', 'newName');
Clone a value to a new key.
db.set('original', { data: 'test' }); db.clone('original', 'copy');
Get the type of a value.
db.type('name'); // 'string' db.type('count'); // 'number' db.type('items'); // 'array' db.type('user'); // 'object' db.type('missing'); // 'undefined'
Deep merge data into an existing object.
db.set('config', { a: 1, b: 2 }); db.merge('config', { b: 3, c: 4 }); // Result: { a: 1, b: 3, c: 4 }
// Initialize array db.set('items', []); // Push - Add to end db.push('items', 'first'); db.push('items', 'second'); // Pop - Remove from end db.pop('items'); // Returns 'second' // Shift - Remove from start db.shift('items'); // Returns 'first' // Unshift - Add to start db.unshift('items', 'new first'); // Splice - Remove/replace elements db.splice('items', 1, 2, 'replacement'); // Filter const evens = db.filter('numbers', n => n % 2 === 0); // Find const user = db.find('users', u => u.id === 1); // FindIndex const index = db.findIndex('users', u => u.id === 1); // Map const names = db.map('users', u => u.name); // Some - At least one matches db.some('numbers', n => n > 10); // true/false // Every - All match db.every('numbers', n => n > 0); // true/false // Reduce const sum = db.reduce('numbers', (acc, n) => acc + n, 0); // IndexOf db.indexOf('items', 'value'); // Returns index or -1 // Includes db.includes('items', 'value'); // true/false // Sort db.sort('numbers'); // Ascending db.sort('numbers', (a, b) => b - a); // Descending // Reverse db.reverse('items'); // Flat - Flatten nested arrays db.flat('nested', 2); // depth = 2 // Unique - Remove duplicates db.unique('items'); // Pull - Remove specific value db.pull('items', 'value');
db.set('score', 100); // Increment/Decrement db.increment('score'); // 101 db.increment('score', 5); // 106 db.decrement('score', 3); // 103 // Add/Subtract db.add('score', 50); // 153 db.subtract('score', 30); // 123 // Multiply/Divide db.multiply('score', 2); // 246 db.divide('score', 3); // 82 // Modulo db.modulo('score', 10); // 2 // Power db.power('score', 2); // 4 // Custom math operation db.math('score', n => Math.sqrt(n)); // 2
db.set('users', [ { name: 'Alice', age: 25, active: true }, { name: 'Bob', age: 30, active: false }, { name: 'Charlie', age: 35, active: true } ]); // Simple query const results = db.query('users') .where('age', '>', 25) .where('active', '==', true) .get(); // With ordering and limit const top2 = db.query('users') .orderBy('age', 'desc') .limit(2) .get(); // Skip for pagination const page2 = db.query('users') .skip(10) .limit(10) .get(); // Get first result const first = db.query('users') .where('active', '==', true) .first(); // Count results const count = db.query('users') .where('age', '>=', 30) .count(); // Available operators: // '==' | '===' | '!=' | '!==' | '>' | '>=' | '<' | '<=' // 'includes' | 'startsWith' | 'endsWith' | 'in' | 'notIn' | 'regex'
// Get or create a collection const users = db.collection('users'); // Insert documents const user = users.insert({ name: 'John', email: 'john@test.com' }); // Returns: { _id: 'uuid', name: 'John', email: '...', _createdAt: '...', _updatedAt: '...' } // Insert many users.insertMany([ { name: 'Alice', age: 25 }, { name: 'Bob', age: 30 } ]); // Find by ID const found = users.findById('uuid'); // Find one by query const alice = users.findOne({ name: 'Alice' }); // Find many with query operators const adults = users.findMany({ age: { $gte: 18 } }); // Available operators: // $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $regex, $exists // Update by ID users.updateById('uuid', { age: 26 }); // Update one by query users.updateOne({ name: 'Alice' }, { age: 27 }); // Update many users.updateMany({ active: false }, { status: 'inactive' }); // Delete by ID users.deleteById('uuid'); // Delete one by query users.deleteOne({ name: 'Bob' }); // Delete many const deletedCount = users.deleteMany({ active: false }); // Count const count = users.count({ active: true }); // Drop collection users.drop();
// Set with TTL (expires in 5 seconds) db.setWithTTL('session', { userId: 123 }, 5000); // Check remaining TTL const ttl = db.getTTL('session'); // milliseconds or null // Make persistent (remove TTL) db.persist('session'); // Listen to expiration db.on('expire', (key) => { console.log(`Key "${key}" expired`); });
// Watch for changes const unwatch = db.watch('user.settings', (newValue, oldValue, key) => { console.log(`${key} changed from`, oldValue, 'to', newValue); }); // Make changes db.set('user.settings.theme', 'dark'); // Triggers watcher // Stop watching unwatch(); // Or unwatch all callbacks for a key db.unwatch('user.settings');
db.set('balance', 100); // Begin transaction db.beginTransaction(); try { db.set('balance', db.get('balance') - 50); db.set('transferred', 50); // Commit changes db.commit(); } catch (error) { // Rollback on error db.rollback(); } // Check transaction state db.inTransaction(); // true/false
// Create backup const backupPath = db.backup(); // Or with custom path const backupPath = db.backup('./backups/mydb-backup.json'); // List available backups const backups = db.listBackups(); // ['./mydb.json.backup-2024εΉ΄01ζ15ζ₯T10-30-00-000Z', ...] // Restore from backup db.restore(backupPath);
// Available events db.on('set', (key, value, oldValue) => {}); db.on('delete', (key, oldValue) => {}); db.on('clear', (oldData) => {}); db.on('save', (data) => {}); db.on('reload', (data) => {}); db.on('import', (data, merge) => {}); db.on('expire', (key) => {}); db.on('backup', (path) => {}); db.on('restore', (path) => {}); db.on('close', () => {}); db.on('transactionBegin', () => {}); db.on('transactionCommit', () => {}); db.on('transactionRollback', () => {});
// Create encrypted database const db = new Datara('./secure.json', { encryption: 'my-secret-password' }); // Data is automatically encrypted on save db.set('secret', 'classified information'); // And decrypted on load console.log(db.get('secret')); // 'classified information' // File content is encrypted with AES-256-GCM
// Enable gzip compression const db = new Datara('./compressed.json', { compression: true }); // Data is automatically compressed/decompressed
const db = new Datara('./validated.json', { schema: { username: { type: 'string', required: true, minLength: 3, maxLength: 20 }, age: { type: 'number', min: 0, max: 150 }, email: { type: 'string', pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ }, role: { type: 'string', enum: ['admin', 'user', 'guest'] }, score: { type: 'number', custom: (value) => value >= 0 || 'Score must be positive' } } }); // Valid data db.set('username', 'john'); // OK db.set('age', 25); // OK // Invalid data throws ValidationError db.set('username', 'ab'); // Error: minLength db.set('age', 200); // Error: max
// Create a plugin const timestampPlugin = { install(datara) { // Add new methods datara.setWithTimestamp = function(key, value) { return this.set(key, { value, createdAt: new Date().toISOString() }); }; } }; // Use the plugin db.use(timestampPlugin); // Use new methods db.setWithTimestamp('item', 'data'); // { value: 'data', createdAt: '2024-01-15T10:30:00.000Z' }
// Async set await db.setAsync('key', 'value'); // Async get const value = await db.getAsync('key'); // Async save await db.saveAsync();
// Get all keys db.keys(); // ['key1', 'key2', ...] db.keys('user'); // Keys starting with 'user' // Get all values db.values(); // [value1, value2, ...] // Get all entries db.entries(); // [['key1', value1], ['key2', value2], ...] // Iterate db.forEach((value, key) => { console.log(key, value); }); // Size db.size(); // Number of top-level keys // Count array items db.count('items'); // Array length db.count('items', item => item.active); // Count with filter // Clear all data db.clear(); // Export database const data = db.export(); // Import data db.import(data); db.import(data, true); // Merge with existing // Reload from file db.reload(); // Close database (cleanup) db.close();
// ES Modules import Datara from 'datara'; // Or import specific classes import { Datara, DataraError, ValidationError } from 'datara';
const { DataraError, ValidationError, EncryptionError, TransactionError } = require('datara'); try { db.set('invalid', value); } catch (error) { if (error instanceof ValidationError) { console.log('Validation failed:', error.key, error.value); } else if (error instanceof EncryptionError) { console.log('Encryption failed'); } }
| Option | Type | Default | Description |
|---|---|---|---|
autoSave |
boolean | true |
Automatically save after each operation |
pretty |
boolean | true |
Pretty print JSON with indentation |
indentSize |
number | 2 |
Indentation size for pretty print |
encryption |
string | null |
Password for AES-256-GCM encryption |
compression |
boolean | false |
Enable gzip compression |
backupInterval |
number | null |
Auto-backup interval in milliseconds |
maxBackups |
number | 5 |
Maximum backup files to keep |
timestamps |
boolean | false |
Add _createdAt/_updatedAt to objects |
schema |
object | null |
Schema validation rules |
MIT Β© devraikou
Contributions, issues and feature requests are welcome!
Give a βοΈ if this project helped you!