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 dataraor
yarn add dataraconst 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 databaseCheck if a key exists.
db.has('username'); // true
db.has('nonexistent'); // falseDelete a key.
db.delete('username'); // true
db.delete('nonexistent'); // falseUpdate a value using a callback function.
db.set('counter', 10);
db.update('counter', val => val * 2); // 20Rename 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)); // 2db.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: '[email protected]' });
// 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-15T10-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/decompressedconst 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!