
OLAP en JavaScript: librerías y ejemplos prácticos
Publicado el:
Tiempo de lectura: 10 min
Tema: Tecnologia
Autor: Leandro Valencia
Cómo hacer analítica tipo OLAP en JavaScript: DuckDB-Wasm, Apache Arrow, Arquero, Perspective, SQL.js y TinyBase, con ejemplos y cuándo usar cada una.
Tabla de Contenidos
- El panorama: motores completos vs. herramientas ligeras
- DuckDB-Wasm: el motor OLAP completo en el navegador
- Apache Arrow (JS) + Arquero: formato columnar más transformación estilo dplyr
- Perspective: motor de pivoteo para dashboards en tiempo real
- SQL.js: SQLite en WebAssembly, simple pero no columnar
- TinyBase: store reactivo ligero, no un motor OLAP
- Tabla comparativa rápida
- Cómo elegir
El panorama: motores completos vs. herramientas ligeras
Antes de entrar librería por librería, una distinción útil. En JavaScript hay dos categorías de solución para "necesito agregar datos sin pegarle a mi base de producción":
Motores OLAP reales compilados a WebAssembly. Ejecutan SQL analítico con almacenamiento columnar, vectorización y optimizador de consultas, igual que un ClickHouse o un BigQuery, pero corriendo dentro del proceso del navegador o de Node. DuckDB-Wasm es el representante principal.
Herramientas de transformación y agregación en memoria. No son motores de base de datos; son librerías que manipulan estructuras de datos ya cargadas (arrays, tablas Arrow, stores reactivos) con operaciones tipo groupBy, sum o pivoteo. Arquero, Perspective y TinyBase caen aquí, cada una con un enfoque distinto.
SQL.js queda en un punto intermedio: es un motor de base de datos real (SQLite), pero orientado a filas, no columnar, así que no escala igual de bien en cargas puramente analíticas aunque se use mucho como sustituto ligero.
DuckDB-Wasm: el motor OLAP completo en el navegador
DuckDB-Wasm es la compilación de DuckDB —el motor analítico embebido que ya mencionamos en la guía de OLAP como la opción por defecto para datasets que caben en una máquina— a WebAssembly. Corre tanto en el navegador como en Node, sin servidor, con el mismo motor columnar vectorizado y el mismo dialecto SQL compatible con PostgreSQL que la versión nativa.
Es la opción más potente de esta lista porque no es una simulación de OLAP: es un optimizador de consultas real, con soporte para leer Parquet, CSV y JSON directamente, incluso por HTTP range requests, sin descargar el archivo completo.
Cuándo usarla: cuando necesitas ejecutar consultas SQL reales —agregaciones, JOINs, ventanas— sobre datasets de tamaño moderado (desde unos MB hasta unos cientos de MB) directamente en el cliente, sin infraestructura de backend. Es la elección natural para dashboards de analítica embebida que cargan un export de datos, herramientas de exploración de datos client-side, o para evitar mandar consultas pesadas a un servidor cuando el archivo ya vive en el navegador del usuario.
Un ejemplo simplificado de cómo se ve una consulta contra un archivo Parquet una vez que el motor está inicializado y conectado:
const result = await connection.query(`
SELECT pais, SUM(importe) AS ingresos
FROM read_parquet('ventas.parquet')
GROUP BY pais
ORDER BY ingresos DESC
`);
console.table(result.toArray());
La inicialización (elegir el bundle de WebAssembly correcto, arrancar el worker, abrir la conexión) tiene varios pasos y cambia entre versiones, así que no la reproduzco aquí: revisa la documentación oficial de DuckDB-Wasm para el setup exacto de la versión que instales.
Apache Arrow (JS) + Arquero: formato columnar más transformación estilo dplyr
Estas dos librerías suelen ir juntas, y conviene entenderlas por separado.
Apache Arrow no es un motor de consultas: es un formato de datos columnar en memoria, estandarizado entre lenguajes (hay implementaciones en Python, R, Java, C++ y JavaScript, entre otros). Su valor está en que muchas herramientas de datos —incluida DuckDB-Wasm— pueden leer y producir Arrow directamente, así que mover datos entre ellas no requiere serializar a JSON ni reconstruir estructuras: se comparte el mismo layout de memoria.
Arquero es una librería de transformación de datos para JavaScript inspirada explícitamente en dplyr de R. Trabaja sobre tablas columnares —arrays, arrays tipados o columnas Arrow— y expone una API encadenable con verbos como filtrar, agrupar, agregar o unir tablas.
Cuándo usarlas: cuando ya tienes datos en formato Arrow (por ejemplo, exportados desde un pipeline de Python o devueltos por DuckDB-Wasm) y quieres encadenar transformaciones tipo roll-up o agregación directamente en JavaScript, sin escribir SQL. Es una buena opción para notebooks de datos en JS, herramientas de exploración interactiva o cuando el equipo ya piensa en términos de dplyr/pandas y prefiere esa sintaxis a SQL.
Un ejemplo simplificado de agregación con Arquero sobre una tabla ya cargada:
import { table } from 'arquero';
const ventas = table({
pais: ['ES', 'MX', 'ES', 'AR'],
importe: [42, 17, 88, 12],
});
const resumen = ventas
.groupby('pais')
.rollup({ ingresos: (d) => op.sum(d.importe) });
console.log(resumen.objects());
La API exacta de importación, los nombres de funciones de agregación (op.sum, op.mean, etc.) y cómo cargar una tabla Arrow con fromArrow() conviene verificarlos en la documentación oficial de Arquero, porque varían entre versiones y según si usas el bundle que incluye Arrow o lo importas aparte.
Perspective: motor de pivoteo para dashboards en tiempo real
Perspective es un motor de agregación y pivoteo construido en C++ y compilado a WebAssembly, con bindings para JavaScript. Nació dentro de J.P. Morgan para dashboards financieros internos y hoy es un proyecto open source bajo la Fundación FINOS.
Lo distintivo de Perspective frente a las demás opciones de esta lista es que está diseñado específicamente para datos que cambian en tiempo real: soporta streaming de actualizaciones, pivoteo interactivo tipo tabla dinámica (agrupar filas y columnas, aplicar agregaciones, ordenar) y viene con sus propios componentes visuales (<perspective-viewer>) listos para insertar en una página.
Cuándo usarla: cuando el caso de uso es un dashboard interactivo donde el usuario final manipula la vista —arrastra dimensiones, cambia agregaciones, filtra— y los datos subyacentes se actualizan en vivo, por ejemplo un panel de trading, un monitor de métricas operacionales o un BI embebido dentro de tu producto. Si solo necesitas correr una consulta puntual y mostrar un resultado fijo, es más motor del que necesitas; para eso encaja mejor DuckDB-Wasm o Arquero.
SQL.js: SQLite en WebAssembly, simple pero no columnar
SQL.js es una compilación de SQLite a WebAssembly que permite correr una base de datos SQLite completa dentro del navegador, sin backend. Es probablemente la librería más veterana de esta lista y la más fácil de adoptar si ya conoces SQL básico.
Aquí hay que ser honesto sobre sus límites: SQLite es una base de datos orientada a filas, igual que Postgres o MySQL. No tiene almacenamiento columnar, ni vectorización, ni optimizador pensado para escanear millones de filas y agregarlas. No es un motor OLAP en el sentido técnico del término.
Aun así, se usa mucho como alternativa ligera para análisis pequeños en el cliente: datasets de unos pocos miles o decenas de miles de filas, donde la diferencia de rendimiento frente a un motor columnar real no se nota, y donde la ventaja es la simplicidad y la madurez de la librería.
Cuándo usarla: para análisis exploratorio de datasets pequeños en el navegador, prototipos rápidos, o cuando necesitas SQL completo (incluyendo escrituras y transacciones) más que rendimiento agregando millones de filas. Si tu dataset crece más allá de eso, migra a DuckDB-Wasm.
TinyBase: store reactivo ligero, no un motor OLAP
TinyBase es un store de datos reactivo pensado para el estado de aplicaciones JavaScript, con un tamaño de librería muy pequeño. No está diseñado como motor analítico: su propósito principal es sincronización de estado, persistencia local y reactividad (que la UI se actualice sola cuando cambian los datos), similar en espíritu a librerías de manejo de estado más que a una base de datos analítica.
Lo incluyo en esta lista porque sí ofrece utilidades de agregación simples —contar, sumar, promediar sobre una tabla— que en apps pequeñas cubren necesidades que de otro modo requerirían montar un motor más pesado.
Cuándo usarla: cuando el "análisis" que necesitas es en realidad una agregación simple sobre datos que ya vive en el estado de tu app —un contador, un total, un promedio que se actualiza en vivo— y no quieres añadir un motor SQL completo solo para eso. No la seleccionaría para nada que se parezca a un dashboard multidimensional o a consultas ad-hoc.
Tabla comparativa rápida
| Librería | Qué es | Motor real de OLAP | Mejor para |
|---|---|---|---|
| DuckDB-Wasm | DuckDB compilado a WASM | Sí, columnar y vectorizado | SQL analítico completo en cliente o Node |
| Apache Arrow (JS) + Arquero | Formato columnar + transformación estilo dplyr | Formato sí, motor de consultas no | Pipelines de transformación en JS sin SQL |
| Perspective | Motor de pivoteo en WASM (FINOS) | Sí, orientado a agregación interactiva | Dashboards en tiempo real con pivoteo |
| SQL.js | SQLite compilado a WASM | No (orientado a filas) | Análisis pequeños, SQL simple en cliente |
| TinyBase | Store reactivo ligero | No | Agregaciones simples sobre estado de app |
Cómo elegir
Si necesitas SQL real sobre un archivo Parquet o CSV de tamaño respetable, sin backend: DuckDB-Wasm, sin dudarlo.
Si ya trabajas con datos en formato Arrow y prefieres encadenar transformaciones en JavaScript en vez de escribir SQL: Arquero.
Si estás construyendo un dashboard interactivo donde el usuario pivotea datos que cambian en vivo: Perspective.
Si tu dataset es pequeño y solo quieres SQL básico sin pretensiones de rendimiento columnar: SQL.js.
Si lo único que necesitas es un contador o un total reactivo dentro del estado de tu app: TinyBase, y probablemente ni siquiera necesites pensar en términos de OLAP.
En todos los casos, antes de escribir código de producción revisa la documentación oficial de la versión que instales: las APIs de inicialización (sobre todo en DuckDB-Wasm y Perspective, que dependen de workers y bundles de WebAssembly) cambian con cierta frecuencia entre versiones.
Preguntas frecuentes
¿Existe un motor OLAP columnar nativo en JavaScript, sin WebAssembly?
No de forma comparable a DuckDB o ClickHouse. Los motores columnares vectorizados de verdad están escritos en C++ o Rust y llegan a JavaScript compilados a WebAssembly (DuckDB-Wasm, Perspective). JavaScript puro no tiene un motor de este tipo con adopción equivalente.
¿Puedo usar DuckDB-Wasm en un backend Node, no solo en el navegador?
Sí. DuckDB-Wasm corre tanto en el navegador como en Node, aunque para un backend puro también existe el binding nativo de DuckDB para Node, que evita la capa de WebAssembly. Cuál conviene depende de si necesitas compartir código entre cliente y servidor.
¿SQL.js sirve para reemplazar una base de datos OLAP real?
No para cargas grandes. SQL.js es SQLite orientado a filas; funciona bien para análisis pequeños en el cliente, pero no escala como un motor columnar en datasets de millones de filas.
¿Arquero necesita Apache Arrow para funcionar?
No para su uso básico sobre arrays normales. Arrow se vuelve relevante cuando quieres interoperar con datos que ya vienen en ese formato (por ejemplo, desde DuckDB-Wasm) o exportar resultados a Arrow.
Posts Relacionados
Continúa explorando contenido similar que te puede interesar

IA para legal: checklist de privacidad y DPA antes de adoptar
Checklist para equipos legales y de compliance: qué exigirle a un proveedor de IA antes de firmar — DPA, retención, opt-out de entrenamiento y certificaciones.

Qwen vs Gemma: cómo elegir tu modelo local en Ollama
Guía práctica para elegir entre Qwen y Gemma al correr modelos de IA en local: código, hardware modesto, tareas multilingües y uso general con Ollama.

DuckDB, ClickHouse, Druid o Pinot: cómo elegir motor OLAP
DuckDB, ClickHouse, Druid y Pinot resuelven problemas distintos. Árbol de decisión y tabla comparativa para elegir el motor OLAP correcto según tu caso de uso.
Alianzas
Herramientas que uso a diario y con las que la comunidad consigue mejores condiciones.