A1-Database: Embedded JSON Database
a1-database is an embedded, zero-dependency, zero-installation JSON database designed for simplicity and portability. As of version 1.8.0, it stores all data in a single file, making it ideal for development, local applications, or scenarios where a lightweight, persistent data store is required without external database server overhead. It operates directly on JavaScript objects, eliminating the need for an ORM, and returns query results as arrays of objects. The package provides methods that cater to both SQL-like (e.g., `insert`, `update` with `id` keys) and document-like (flexible `save` with custom filter functions for multi-key or heterogeneous data) paradigms. Each database instance is represented by a single file, facilitating easy backup and data dumping. Its primary release cadence is not explicitly stated, but ongoing development is implied by the version number, focusing on a straightforward API for common CRUD operations like `save`, `find`, and `delete`.
Common errors
-
Error: Item with ID [ID_VALUE] already exists.
cause This error occurs when attempting to use `db.insert()` with an item whose `id` field matches an existing record in the database.fixTo fix this, either ensure that the `id` is unique before calling `db.insert()`, or use `db.save()` instead if the intention is to update/overwrite the existing item with the same `id`.
Warnings
- gotcha Database file paths are resolved relative to `process.CWD()` (Current Working Directory) where the Node.js process was started, not relative to the JavaScript file where `a1-database` is instantiated. This can lead to unexpected file locations if not explicitly managed.
- gotcha The `save` method automatically updates existing items if an `id` property is present in the item(s) being saved, acting as an upsert. For items without an `id` or when using a custom `filter` function, `save` will append new items or replace items matching the filter, requiring careful filter definition to prevent unintended duplicates or data loss.
- gotcha The `insert` method enforces uniqueness based on the `id` field. Attempting to `insert` an item with an `id` that already exists in the database will throw an error, unlike `save` which overwrites. Developers should choose `insert` for strict 'no-duplicate-ID' policies and `save` for 'upsert' behavior.
- gotcha As a file-based embedded database, `a1-database` performs disk I/O for every write operation. While suitable for many use cases, high-frequency write operations or very large datasets may experience performance bottlenecks compared to in-memory or server-based databases. Automatic compaction is triggered every 10,000 consecutive save/delete operations.
Install
-
npm install a1-database -
yarn add a1-database -
pnpm add a1-database
Imports
- database
import database from 'a1-database'
const database = require('a1-database')
Quickstart
const database = require('a1-database');
const fs = require('fs/promises'); // For cleanup
async function runExample() {
const dbPath = 'users.db';
try {
// Ensure cleanup of previous runs for a fresh start
try { await fs.unlink(dbPath); } catch (e) { /* ignore if file doesn't exist */ }
const db = await database.get(dbPath);
console.log('Database connected to', dbPath);
// Save initial data
await db.save({ name: 'Juan', email: 'juan@example.com' });
await db.save({ name: 'Maria', email: 'maria@example.com' });
console.log('Initial users saved.');
// Save with an ID, demonstrating upsert behavior
await db.save([{ id: 100, value: 'old test data' }]);
console.log('Saved item with id 100 (old).');
await db.save([{ id: 100, value: 'new test data', timestamp: Date.now() }]); // item with id, so old items are removed
console.log('Saved item with id 100 (new), overwriting old data.');
// Find operations
const juan = await db.findOne(el => el.name === 'Juan');
console.log('Found Juan:', juan);
const allUsers = await db.find(el => el.name === 'Juan' || el.name === 'Maria');
console.log('Found all initial users:', allUsers);
// Demonstrate existence check
const existsJuan = await db.exists(el => el.name === 'Juan');
console.log('Does Juan exist?', !!existsJuan);
// Delete operation
const deletedCount = await db.delete(el => el.email === 'maria@example.com');
console.log(`Deleted ${deletedCount} user(s).`);
const remainingUsers = await db.find(el => true);
console.log('Remaining items after delete:', remainingUsers);
// Disconnect from the database
await database.disconnect(db);
console.log('Database disconnected.');
} catch (error) {
console.error('An error occurred:', error);
} finally {
// Optional: Clean up the database file after the example
try { await fs.unlink(dbPath); } catch (e) { /* ignore */ }
console.log('Cleaned up database file.');
}
}
runExample().catch(console.error);