PostgreSQL JSONB: por qué dejé de considerar MongoDB
PostgreSQL tiene soporte JSON nativo desde hace 10 años. Con índices GIN, validación de schema y joins relacionales, hace la mayoría de casos de uso de MongoDB innecesarios. Un análisis técnico.
softw.engineer
Software Engineer · softw.engineer

PostgreSQL JSONB: por qué dejé de considerar MongoDB
He usado PostgreSQL y MongoDB en producción. Durante años, la narrativa fue clara: MongoDB para datos no estructurados, PostgreSQL para datos relacionales. Esa narrativa quedó obsoleta hace tiempo. PostgreSQL con JSONB es, para la mayoría de casos de uso, un mejor MongoDB que MongoDB.
Lo que JSONB realmente hace
JSONB es un tipo de dato binario de PostgreSQL que almacena JSON de forma eficiente. La diferencia clave con JSON regular: JSONB está indexado y parseado al momento del insert. Esto permite queries complejas sobre campos JSON a velocidad casi nativa.
-- Crear tabla con columna JSONB
CREATE TABLE events (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
data JSONB NOT NULL
);
-- Insertar eventos con estructura arbitraria
INSERT INTO events (user_id, data) VALUES
(1, '{"type": "login", "device": "iPhone", "location": "Lima"}'),
(2, '{"type": "purchase", "amount": 49.99, "currency": "USD", "items": 3}'),
(1, '{"type": "pageview", "url": "/pricing", "duration_s": 45}');
Cada evento tiene estructura diferente. Sin schema rígido. Sin migraciones cuando añades campos nuevos. Exactamente la promesa de MongoDB, pero sobre PostgreSQL.
Queries sobre JSON: el poder real
-- Acceder a campos anidados con ->
SELECT data->>'type' AS event_type, data->>'amount' AS amount
FROM events
WHERE data->>'type' = 'purchase';
-- Filtrar por valor numérico dentro del JSON
SELECT * FROM events
WHERE (data->>'amount')::numeric > 30;
-- Buscar dentro de arrays en JSON
SELECT * FROM events
WHERE data @> '{"type": "login"}';
-- Extraer campos anidados profundos
SELECT data->'location'->>'city' AS city
FROM events
WHERE data->>'type' = 'login';
El operador @> (contains) es particularmente poderoso. Verifica si un JSON contiene cierta estructura. Con un índice GIN, esto es casi instantáneo en millones de filas.
Índices GIN: velocidad de MongoDB sobre PostgreSQL
La razón por la que MongoDB es rápido para documentos: índices sobre campos JSON. PostgreSQL hace exactamente lo mismo con índices GIN.
-- Crear índice GIN sobre la columna JSONB
CREATE INDEX idx_events_data ON events USING GIN (data);
-- Queries que usan este índice:
SELECT * FROM events WHERE data @> '{"type": "login"}'; -- ✓ usa índice
SELECT * FROM events WHERE data ? 'amount'; -- ✓ usa índice
Con un índice GIN, una búsqueda sobre data @> '{"type": "login"}' en 10 millones de filas toma milisegundos, no segundos. Misma velocidad que MongoDB.
Índices sobre campos específicos dentro del JSON:
-- Índice sobre un campo específico del JSON
CREATE INDEX idx_events_type ON events ((data->>'type'));
-- Query optimizada
SELECT * FROM events WHERE data->>'type' = 'purchase';
Lo que PostgreSQL hace mejor que MongoDB
Joins. Esta es la razón número uno. En MongoDB, joins son un patrón que requiere múltiples queries o aggregation pipelines complejos. En PostgreSQL:
-- Eventos de compra con datos del usuario y producto, todo en una query
SELECT
u.name,
u.email,
e.data->>'amount' AS amount,
e.data->>'currency' AS currency,
p.name AS product_name
FROM events e
JOIN users u ON e.user_id = u.id
JOIN products p ON (e.data->>'product_id')::int = p.id
WHERE e.data->>'type' = 'purchase'
ORDER BY e.created_at DESC;
Una query. Joins entre datos relacionales (users, products) y datos JSON (eventos). Lo mejor de ambos mundos.
Transacciones ACID. PostgreSQL garantiza que una transacción se completa íntegramente o se revierte. MongoDB tiene transacciones multi-document desde 4.0, pero son más lentas y menos maduras.
Full-text search. PostgreSQL tiene tsvector y tsquery para búsqueda de texto completo. Más poderoso que el $text de MongoDB.
-- Búsqueda full-text sobre campos JSON
SELECT * FROM articles
WHERE to_tsvector('spanish', data->>'content') @@ to_tsquery('spanish', 'docker & contenedores');
Validación de schema. MongoDB tiene validator, pero PostgreSQL lo hace mejor con constraints:
-- Validar que ciertos campos existan en el JSON
ALTER TABLE events
ADD CONSTRAINT check_event_type
CHECK (data ? 'type');
-- Validar tipos dentro del JSON
ALTER TABLE events
ADD CONSTRAINT check_amount
CHECK (
data->>'type' != 'purchase' OR
(data->>'amount')::numeric > 0
);
Cuándo MongoDB sigue siendo la mejor opción
No todo es PostgreSQL. Hay casos donde MongoDB gana legítimamente:
Sharding horizontal a escala masiva. Si tienes petabytes de datos distribuidos en docenas de servidores, el sharding nativo de MongoDB es más simple que el de PostgreSQL (que requiere extensiones como Citus).
Documentos jerárquicos muy profundos. Si tus documentos tienen 5+ niveles de nesting anidado, MongoDB los maneja mejor. PostgreSQL puede, pero las queries se vuelven complejas.
Equipos que ya dominan MongoDB. Si tu equipo sabe MongoDB y no tiene experiencia con PostgreSQL, la curva de migración puede no valer la pena.
Schema que cambia constantemente. Si tu schema evoluciona semanalmente y las migraciones son dolorosas, MongoDB te da más flexibilidad. PostgreSQL tiene migraciones, pero requieren más disciplina.
El framework de decisión
Mi proceso para elegir base de datos:
- ¿Necesitas joins complejos? → PostgreSQL
- ¿Tu schema es relativamente estable? → PostgreSQL
- ¿Necesitas consistencia transaccional fuerte? → PostgreSQL
- ¿Tienes datos relacionales + semi-estructurados mixtos? → PostgreSQL (JSONB)
- ¿Necesitas escalar horizontalmente a petabytes? → Considera MongoDB
- ¿Tu schema cambia semanalmente sin control? → Considera MongoDB
- ¿No estás seguro? → PostgreSQL
El 80% de las aplicaciones caen en 1-4. PostgreSQL con JSONB cubre sus necesidades.
Un ejemplo real: analytics de eventos
Escenario: plataforma SaaS que trackea eventos de usuario. Cada evento tiene campos comunes (user_id, timestamp, type) pero campos específicos variables según el tipo.
Con MongoDB:
// Colección events, documentos con estructura variable
db.events.insertOne({
user_id: 1,
type: 'purchase',
amount: 49.99,
items: [101, 102]
})
db.events.insertOne({
user_id: 1,
type: 'pageview',
url: '/pricing',
duration: 45
})
Con PostgreSQL + JSONB:
INSERT INTO events (user_id, data) VALUES
(1, '{"type": "purchase", "amount": 49.99, "items": [101, 102]}'),
(1, '{"type": "pageview", "url": "/pricing", "duration": 45}');
La diferencia: en PostgreSQL puedo hacer joins con la tabla users para enriquecer los eventos. En MongoDB, necesito una query separada y unir en la aplicación.
-- En PostgreSQL: todo en una query
SELECT
u.name,
u.plan,
COUNT(*) FILTER (WHERE e.data->>'type' = 'purchase') AS purchases,
AVG((e.data->>'amount')::numeric) FILTER (WHERE e.data->>'type' = 'purchase') AS avg_amount
FROM events e
JOIN users u ON e.user_id = u.id
WHERE e.created_at > NOW() - INTERVAL '30 days'
GROUP BY u.name, u.plan;
En MongoDB, esto requiere un aggregation pipeline de 4 etapas. Más verboso. Más difícil de debuggear.
Migración de MongoDB a PostgreSQL
Si estás considerando migrar:
- Identifica qué colecciones son realmente no-relacionales. Sorpresa: la mayoría sí lo son.
- Crea tablas relacionales para datos estructurados. Users, products, orders. Estos no necesitan JSON.
- Usa JSONB solo para datos genuinamente flexibles. Eventos, metadata, configuración.
- Migra incrementalmente. Una colección a la vez. Dual-write durante la transición.
Las herramientas: pgloader automatiza gran parte del proceso. mongoexport + COPY de PostgreSQL para datos simples.
La realidad del landscape en 2026
El stack más popular para startups en 2026 no es MongoDB + Express + Node. Es PostgreSQL + Prisma + Next.js.
La gente votó con sus repos. Y PostgreSQL ganó.
MongoDB sigue siendo una excelente base de datos para ciertos casos. Pero para la mayoría de aplicaciones que evalúan ambas opciones, PostgreSQL con JSONB es la mejor elección técnica: relaciones + JSON + transacciones + full-text search + extensibilidad geoespacial (PostGIS), todo en un motor.
El mito de "MongoDB es mejor para datos no estructurados" quedó obsoleto cuando PostgreSQL añadió JSONB hace una década. Si no lo has mirado últimamente, mira. El PostgreSQL de 2026 es un motor diferente.
Recursos:
- PostgreSQL JSONB docs — documentación oficial
- JSONB indexing in PostgreSQL — índices GIN detallados
- pgloader — migración MongoDB → PostgreSQL
¿Qué te pareció esto?
Tu feedback nos ayuda a crear mejor contenido
¿Qué opinas?
Déjanos tu comentario o pregunta sobre este artículo.