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

datara

v2.0.0

Published

Modern, feature-rich JSON database module for Node.js with encryption, compression, transactions, and more

Readme

🗄️ Datara v2.0

Modern, feature-rich and secure JSON database module for Node.js.

License: MIT Node.js Version

✨ Features

Core Features

  • 🚀 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

New in v2.0

  • 🔐 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

📦 Installation

npm install datara

or

yarn add datara

🚀 Quick Start

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();

📖 Documentation

Initialization

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 }
  }
});

Basic Operations

set(key, value)

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');

get(key, defaultValue)

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

has(key)

Check if a key exists.

db.has('username'); // true
db.has('nonexistent'); // false

delete(key)

Delete a key.

db.delete('username'); // true
db.delete('nonexistent'); // false

update(key, callback)

Update a value using a callback function.

db.set('counter', 10);
db.update('counter', val => val * 2); // 20

rename(oldKey, newKey)

Rename a key.

db.set('oldName', 'value');
db.rename('oldName', 'newName');

clone(sourceKey, destKey)

Clone a value to a new key.

db.set('original', { data: 'test' });
db.clone('original', 'copy');

type(key)

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'

merge(key, data)

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 }

Array Operations

// 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');

Math Operations

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

Query Builder

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'

Collection API (MongoDB-like)

// 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();

TTL (Time-To-Live)

// 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/Observer

// 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');

Transactions

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

Backup/Restore

// 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);

Events

// 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', () => {});

Encryption

// 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

Compression

// Enable gzip compression
const db = new Datara('./compressed.json', {
  compression: true
});

// Data is automatically compressed/decompressed

Schema Validation

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

Plugin System

// 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 Operations

// Async set
await db.setAsync('key', 'value');

// Async get
const value = await db.getAsync('key');

// Async save
await db.saveAsync();

Utility Methods

// 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();

ESM Support

// ES Modules
import Datara from 'datara';

// Or import specific classes
import { Datara, DataraError, ValidationError } from 'datara';

Error Classes

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');
  }
}

🔧 Configuration Options

| 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 |

📄 License

MIT © devraikou

🤝 Contributing

Contributions, issues and feature requests are welcome!

⭐ Show your support

Give a ⭐️ if this project helped you!