Skip to content

Latest commit

 

History

History
119 lines (84 loc) · 3.77 KB

File metadata and controls

119 lines (84 loc) · 3.77 KB

Getting Started with SencilloDB

Installation

npm install sencillodb

SencilloDB is written in TypeScript and ships its own type definitions. It is ESM only and requires Node 18 or newer.

Should you use it?

Use SencilloDB when your Node app wants durable local JSON data with transactions, indexes and migrations, but you do not want to run a database server. It is a strong fit for CLIs, desktop apps, prototypes, small internal tools, build caches, bots and tests.

Reach for a server database instead when you need many high-frequency writers, complex joins or analytics, replication, remote sync, database-enforced permissions, or storage on an unreliable network filesystem. The longer decision guide is Use Cases and Limits.

Your first store

import { SencilloDB } from "sencillodb";

const db = new SencilloDB({ file: "./my-database.json" });

const user = await db.transaction(async (tx) => {
  return tx.create({
    collection: "users",
    data: { name: "Alice", age: 30 },
  });
});

console.log(user); // { name: "Alice", age: 30, _id: 1 }

The file is created for you if it does not exist (including any missing parent folders). Every write happens inside a transaction, and nothing reaches disk until the callback returns without throwing.

Reading data back

const adults = await db.transaction((tx) =>
  tx.findMany({
    collection: "users",
    filter: { age: { $gte: 18 } },
    sort: (a, b) => a.age - b.age,
    limit: 10,
  })
);

const total = await db.transaction((tx) => tx.count({ collection: "users" }));

find returns the first match (or undefined), findMany returns an array, count returns a number.

Updating and deleting

await db.transaction(async (tx) => {
  // patch a few fields
  await tx.update({ collection: "users", _id: 1, $set: { age: 31 } });

  // replace the whole document
  await tx.update({ collection: "users", _id: 1, data: { name: "Alice", age: 31 } });

  // patch everything matching a filter
  await tx.updateMany({ collection: "users", filter: { age: { $lt: 18 } }, $set: { minor: true } });

  await tx.destroy({ collection: "users", _id: 1 });
});

Speeding up lookups

A secondary index turns a scan into a direct lookup, and can enforce uniqueness:

await db.transaction(async (tx) => {
  await tx.ensureIndex({ collection: "users", field: "email", unique: true });
});

// uses the index
const alice = await db.transaction((tx) =>
  tx.find({ collection: "users", filter: { email: "alice@example.com" } })
);

Picking a storage mode

Mode Config Good for
Single file { file: "./app.json" } Small stores, easy to inspect and copy
Folder { folder: "./data" } Many collections, only touched ones load and save
Sharded { folder: "./data", sharding: true } Large collections split across index buckets

See Persistence Modes for the trade-offs.

A practical first setup

Start with one file unless you already know why you need another layout:

const db = new SencilloDB({
  file: "./data/app.json",
  aof: true,
});

That gives you the simplest file layout plus cheap append-only commits. Add lock: true only if more than one process can write to the same store. Run compact() occasionally so the append only log does not grow forever:

await db.compact();

Next steps