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

lite-nosql

v1.0.1

Published

Embedded NoSQL document database for Node.js — no binaries, file-based, WAL + snapshot durability

Readme

lite-nosql

Embedded NoSQL document database for Node.js
Sem binários nativos · apenas filesystem · funciona em shared hosting

Node ≥18 License: MIT


Características

| Característica | Detalhe | |---|---| | Zero binários nativos | Usa apenas fs, path, crypto | | Durabilidade WAL + Snapshot | Inspirado em SQLite; crash-safe | | CJS + ESM | Funciona com require() e import | | TypeScript | Declarações .d.ts incluídas | | Índices em memória | Lookups rápidos em campos indexados | | Concorrência | Fila de escrita serializada + file lock | | Filtros ricos | $gt, $gte, $lt, $lte, $ne, $in, $nin, $regex | | Sem dependências | dependencies: {} — zero pacotes externos |


Instalação

npm install lite-nosql

Exemplo Completo

import { abrirBanco } from "lite-nosql";   // ESM
// const { abrirBanco } = require("lite-nosql"); // CommonJS

const db = await abrirBanco({
  pasta: "./dados",
  modoDuravel: true,   // fsync em cada escrita (recomendado em produção)
  debug: false,
});

const users = db.colecao("users", { indices: ["email", "createdAt"] });

// Inserir
const id = await users.inserir({ nome: "Ana", email: "[email protected]" });

// Buscar por _id
const ana = await users.buscarUm({ _id: id });
console.log(ana); // { _id: "...", nome: "Ana", email: "[email protected]", createdAt: "...", updatedAt: "..." }

// Actualizar
await users.actualizarUm({ _id: id }, { $set: { nome: "Ana Maria" } });
await users.actualizarUm({ _id: id }, { $inc: { loginCount: 1 } });
await users.actualizarUm({ _id: id }, { $unset: ["campoObsoleto"] });

// Buscar com filtro, ordenação e paginação
const lista = await users.buscar(
  { email: "[email protected]" },
  { limite: 50, saltar: 0, ordenarPor: "createdAt", ordem: "desc" }
);

// Buscar com operadores
const recentes = await users.buscar({ createdAt: { $gt: "2024-01-01T00:00:00.000Z" } });
const especificos = await users.buscar({ email: { $in: ["[email protected]", "[email protected]"] } });

// Contar
const total = await users.contar();
const activos = await users.contar({ status: "activo" });

// Remover
await users.removerUm({ _id: id });

// Compactar manualmente (opcional — ocorre automaticamente)
await users.compactar();

// Fechar o banco (aguarda escritas pendentes)
await db.fechar();

API

abrirBanco(opcoes)Promise<Banco>

Abre (ou cria) um banco de dados no directório especificado.

| Opção | Tipo | Padrão | Descrição | |---|---|---|---| | pasta | string | obrigatório | Directório de armazenamento | | modoDuravel | boolean | true | Se true, faz fsync em cada escrita | | limiteWAL | number | 5242880 (5 MB) | Bytes de WAL antes de compactar | | debug | boolean | false | Activar logs detalhados | | serializar | object | null | Serializer personalizado (ver abaixo) |


Banco

banco.colecao(nome, opcoes?)Colecao

Obtém ou cria uma colecção. Múltiplas chamadas com o mesmo nome retornam a mesma instância.

| Opção | Tipo | Descrição | |---|---|---| | indices | string[] | Campos a indexar para lookups eficientes |

banco.fechar()Promise<void>

Aguarda escritas pendentes e liberta recursos.


Colecao

inserir(doc)Promise<string>

Insere um documento. Gera _id automaticamente se ausente. Adiciona createdAt e updatedAt.

const id = await col.inserir({ nome: "Alice", idade: 30 });

buscar(filtro?, opcoes?)Promise<Documento[]>

Retorna documentos que correspondem ao filtro.

// Sem filtro — todos os documentos
await col.buscar();

// Igualdade simples
await col.buscar({ status: "activo" });

// Operadores
await col.buscar({ idade: { $gte: 18, $lt: 65 } });
await col.buscar({ nome: { $regex: /^Ana/i } });
await col.buscar({ role: { $in: ["admin", "editor"] } });

// Com opções
await col.buscar({}, { limite: 20, saltar: 40, ordenarPor: "nome", ordem: "asc" });

Operadores de filtro suportados:

| Operador | Significado | |---|---| | $gt | maior que | | $gte | maior ou igual | | $lt | menor que | | $lte | menor ou igual | | $ne | diferente de | | $in | valor está na lista | | $nin | valor não está na lista | | $regex | correspondência de regex |

buscarUm(filtro?)Promise<Documento \| null>

Retorna o primeiro documento correspondente, ou null.

actualizarUm(filtro, update)Promise<boolean>

Actualiza o primeiro documento correspondente. Retorna true se encontrado.

Operadores de update:

| Operador | Exemplo | Efeito | |---|---|---| | $set | { $set: { nome: "Bob" } } | Define campos | | $unset | { $unset: ["campo"] } | Remove campos | | $inc | { $inc: { visitas: 1 } } | Incrementa campo numérico |

removerUm(filtro)Promise<boolean>

Remove o primeiro documento correspondente. Retorna true se encontrado.

contar(filtro?)Promise<number>

Conta documentos. Sem filtro, retorna o total da colecção.

compactar()Promise<void>

Força a compactação imediata: escreve snapshot e zera o WAL.


Armazenamento e Durabilidade

Ficheiros por colecção

dados/
  users.snapshot.json   ← estado compacto (JSON)
  users.wal.log         ← journal append-only
  users.lock            ← lock temporário de escrita

Formato do WAL

Cada linha é um objecto JSON:

{"op":"insert","ts":1700000000000,"id":"abc123","doc":{"_id":"abc123","nome":"Ana",...}}
{"op":"update","ts":1700000001000,"id":"abc123","set":{"nome":"Ana Maria"},"unset":[],"inc":{}}
{"op":"delete","ts":1700000002000,"id":"abc123"}

Ciclo de vida

Escrita → append WAL → [fsync] → actualizar memória
Leitura → sempre da memória (cache quente)
Startup → carregar snapshot → reaplicar WAL
Compactação → snapshot atómico (rename) → zerar WAL

Compactação

Ocorre automaticamente quando o WAL excede limiteWAL. Processo seguro:

  1. Escrever snapshot temporário (.tmp)
  2. fsync
  3. rename atómico
  4. Zerar WAL

Concorrência

Dentro do mesmo processo

A fila de escrita serializada (_filaEscrita) garante que inserts/updates/deletes paralelos são processados em sequência. Leituras são sempre servidas da memória.

Entre múltiplos processos

O lock de ficheiro (colecao.lock) usa O_EXCL para exclusividade. Cada processo tenta adquirir o lock com backoff exponencial antes de compactar.

Atenção: Para múltiplos processos simultâneos a fazer escritas normais (não compactação), a arquitectura WAL append-only já é segura no mesmo filesystem POSIX — escritas ao nível de write() syscall são atómicas para blocos pequenos. Para workloads multi-processo intensivos, considere uma arquitectura cliente-servidor.


Índices

  • _id é sempre indexado (via Map directa, O(1))
  • Índices opcionais por campo são Map<valor, Set<_id>> em memória
  • Filtros em campos indexados usam o índice automaticamente
  • Filtros em campos não indexados fazem varredura completa (com aviso em modo debug)
  • Os índices são reconstruídos na abertura do banco
const col = db.colecao("posts", { indices: ["autorId", "createdAt", "status"] });

Serializer Personalizado

const db = await abrirBanco({
  pasta: "./dados",
  serializar: {
    serializar: (valor) => JSON.stringify(valor),          // snapshot → string
    deserializar: (raw) => JSON.parse(raw),               // string → snapshot
  }
});

Útil para compressão, encriptação, ou substituição de JSON por MessagePack.


Limitações

| Limitação | Notas | |---|---| | Tudo em memória | Todos os documentos são mantidos em RAM. Não adequado para colecções com centenas de MB de dados | | Sem transações | Não há atomicidade entre múltiplas colecções | | Sem joins/agregações | Processamento ad-hoc deve ser feito na aplicação | | Concorrência multi-processo | Escrita simultânea de múltiplos processos Node.js é segura ao nível do WAL; compactação usa file lock | | Sem query planner | Apenas índices de igualdade; filtros compostos fazem varredura parcial | | Node.js ≥18 | Usa node:test, crypto.randomBytes |


Sugestões de Nomes npm (alternativas)

Caso lite-nosql esteja ocupado:

  • filenosql
  • nodefiledb
  • waldb
  • snapdb-node
  • embeddedoc

Licença

MIT