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.
- 🧩 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
- npm i jacksdb
import { JacksDB, Schema } from "jacksdb"; // or from your relative path
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,
},
});
const db = new JacksDB("your-secret-key"); // secret-key optional
const users = db.collection("users", userSchema); // Collection name and schema
- 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(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" });
- updateOne(filter, update)
await users.updateOne({ id: 1 }, { name: "Mona", age: 31 });
- updateMany(filter, update)
await users.updateMany({ tags: "blogger" }, { "meta.active": false });
- deleteOne(query)
await users.deleteOne({ name: "Mona" });
- deleteMany(query)
await users.deleteMany({ "meta.city": "Delhi" });
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 |
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 |