Embedded NoSQL document database for Node.js
Sem binários nativos · apenas filesystem · funciona em shared hosting
| 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 |
npm install lite-nosqlimport { 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: "ana@x.com" });
// Buscar por _id
const ana = await users.buscarUm({ _id: id });
console.log(ana); // { _id: "...", nome: "Ana", email: "ana@x.com", 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: "ana@x.com" },
{ 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: ["a@a.com", "b@b.com"] } });
// 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();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) |
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 |
Aguarda escritas pendentes e liberta recursos.
Insere um documento. Gera _id automaticamente se ausente. Adiciona createdAt e updatedAt.
const id = await col.inserir({ nome: "Alice", idade: 30 });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 |
Retorna o primeiro documento correspondente, ou null.
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 |
Remove o primeiro documento correspondente. Retorna true se encontrado.
Conta documentos. Sem filtro, retorna o total da colecção.
Força a compactação imediata: escreve snapshot e zera o WAL.
dados/
users.snapshot.json ← estado compacto (JSON)
users.wal.log ← journal append-only
users.lock ← lock temporário de escrita
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"}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
Ocorre automaticamente quando o WAL excede limiteWAL. Processo seguro:
- Escrever snapshot temporário (
.tmp) fsyncrenameatómico- Zerar WAL
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.
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.
_idé sempre indexado (viaMapdirecta, 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"] });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çã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 |
Caso lite-nosql esteja ocupado:
filenosqlnodefiledbwaldbsnapdb-nodeembeddedoc
MIT