jacksdb
v1.3.17
Published
**JacksDB** is a secure, local-first, file-based document database built in TypeScript. It uses AES-256-CBC encryption, per-field indexing (including nested fields), and MongoDB-style APIs for inserting, querying, updating, and deleting documents — all fr
Readme
🧩 JacksDB – Encrypted JSON Document Database
JacksDB is a secure, local-first, file-based document database built in TypeScript. It uses AES-256-CBC encryption, per-field indexing (including nested fields), and MongoDB-style APIs for inserting, querying, updating, and deleting documents — all from the filesystem, with no external dependencies.
📦 Features
- 🧩 MongoDB-style API (
insertOne,insertMany,find,updateOne,deleteOne, etc.) - 🔐 AES-256 encrypted storage
- 🗂️ Per-field and nested key indexing
- ⚡ Efficient in-place updates (if new data fits)
- 🧼 Background-safe deletion with
removeGarbage() - 📁 Fully file-based – no server required
✅ Usage
Installation
- npm i jacksdb
import jacksdb from "jacksdb"; // or from your relative path
const { JacksDB, Schema } = jacksdb;Define a Schema
You must define a schema using Schema before using a collection:
const userSchema = new Schema({
id: Number,
name: String,
age: Number,
tags: [String],
meta: {
city: String,
active: Boolean,
},
});Initialize JacksDB
const db = new JacksDB({ db: "DB_NAME", secret: "SECRET" }); // secret-key optionalCreate Collections
const users = db.collection("users", userSchema); // Collection name and schemaInsert Data
- insertOne(doc: object)
await users.insertOne({
id: 1,
name: "Alice",
age: 30,
tags: ["engineer", "blogger"],
meta: { city: "Delhi", active: true },
});- insertMany(docs: object[])
await users.insertMany([
{
id: 2,
name: "Bob",
age: 25,
tags: ["coder"],
meta: { city: "Mumbai", active: false },
},
{
id: 3,
name: "Charlie",
age: 35,
tags: ["dev"],
meta: { city: "Delhi", active: true },
},
]);Find Documents
- find(query, options?)
const result = await users.find({ age: 30 });Optional query options:
await users.find(
{},
{
sort: { age: -1 },
skip: 10,
limit: 5,
}
);- findOne(query)
const user = await users.findOne({ name: "Alice" });Update Documents
- updateOne(filter, update)
await users.updateOne({ id: 1 }, { name: "Mona", age: 31 });- updateMany(filter, update)
await users.updateMany({ tags: "blogger" }, { "meta.active": false });Delete Documents
- deleteOne(query)
await users.deleteOne({ name: "Mona" });- deleteMany(query)
await users.deleteMany({ "meta.city": "Delhi" });Supported Query Operators
| Operator | Usage Example | Description |
| --------- | ------------------------------------------------------------- | --------------------- |
| $eq | { age: { $eq: 30 } } | Equal to |
| $ne | { name: { $ne: "Bob" } } | Not equal to |
| $gt | { age: { $gt: 25 } } | Greater than |
| $gte | { age: { $gte: 30 } } | Greater than or equal |
| $lt | { age: { $lt: 40 } } | Less than |
| $lte | { age: { $lte: 35 } } | Less than or equal |
| $in | { "meta.city": { $in: ["Delhi", "Pune"] } } | In array |
| $nin | { "meta.city": { $nin: ["Mumbai"] } } | Not in array |
| $exists | { "meta.city": { $exists: true } } | Field exists |
| $and | { $and: [ { age: { $gt: 30 } }, { "meta.active": true } ] } | Logical AND |
| $or | { $or: [ { name: "Alice" }, { age: { $lt: 25 } } ] } | Logical OR |
Time Complexity
| Operation | Time Complexity | Description |
| ----------------- | ------------------------------- | ------------------------------- |
| insertOne() | O(1 + f) | f = number of indexed fields |
| find() | O(1) with index, O(n) full scan | Uses indexes if available |
| updateOne() | O(f) | Clean + reindex affected fields |
| deleteOne() | O(f) | Clean index entries |
| insertMany() | O(k × f) | k = number of documents |
| updateMany() | O(n × f) | For each matched document |
| deleteMany() | O(n × f) | Same as updateMany |
| fullScan() | O(n) | Streamed read of all documents |
| removeGarbage() | O(n) | Rewrites only valid blocks |
