Como desarrollador, la elección entre PostgreSQL y MongoDB puede tener un impacto significativo en el éxito de tu proyecto. Después de implementar ambas bases de datos en diversos proyectos, desde startups hasta empresas establecidas, quiero compartir las lecciones que he aprendido en el camino.
Antes de sumergirnos en el código, hablemos de nuestro contexto:
- Recursos de hosting limitados
- Necesidad de optimizar costos
- Importancia de la escalabilidad gradual
Modelado de Datos
PostgreSQL: Enfoque Relacional
-- Ejemplo de modelo relacional para una tienda en línea
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
nombre VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE productos (
id SERIAL PRIMARY KEY,
nombre VARCHAR(255) NOT NULL,
precio DECIMAL(10,2) NOT NULL,
stock INTEGER NOT NULL
);
CREATE TABLE ordenes (
id SERIAL PRIMARY KEY,
usuario_id INTEGER REFERENCES usuarios(id),
total DECIMAL(10,2) NOT NULL,
estado VARCHAR(50) DEFAULT 'pendiente'
);
Este modelo relacional:
- Garantiza integridad referencial
- Facilita reportes complejos
- Mantiene consistencia en los datos
- Ideal para transacciones financieras
MongoDB: Enfoque Documental
db.usuarios.insertOne({
email: "[email protected]",
nombre: "Juan Pérez",
ordenes: [
{
productos: [
{
nombre: "Laptop Developer Pro",
precio: 1299.99,
cantidad: 1
}
],
total: 1299.99,
estado: "pendiente"
}
],
created_at: new Date()
})
Este modelo documental:
- Reduce joins innecesarios
- Facilita cambios en la estructura
- Mejora performance en lecturas
- Ideal para datos que cambian frecuentemente
Escenarios Prácticos
1. Sistema de Logging
CREATE TABLE logs (
id SERIAL PRIMARY KEY,
nivel VARCHAR(20),
mensaje TEXT,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
metadata JSONB
);
-- Consulta con filtros específicos
SELECT * FROM logs
WHERE nivel = 'ERROR'
AND timestamp > NOW() - INTERVAL '1 day'
AND metadata->>'service' = 'payment';
Esta implementación:
- Permite búsquedas estructuradas
- Facilita análisis temporal
- Soporta datos JSON para flexibilidad
- Mantiene consistencia histórica
MongoDB
db.logs.insertOne({
nivel: "ERROR",
mensaje: "Fallo en procesamiento de pago",
timestamp: new Date(),
metadata: {
service: "payment",
transactionId: "123456",
errorCode: "PAY_001"
}
})
// Consulta equivalente
db.logs.find({
nivel: "ERROR",
timestamp: {
$gt: new Date(Date.now() - 24*60*60*1000)
},
"metadata.service": "payment"
})
Este enfoque:
- Permite estructura flexible
- Facilita inserción rápida
- Ideal para alto volumen de escrituras
- Mejor para datos no estructurados
2. Sistema de E-commerce
PostgreSQL: Búsqueda de Productos
-- Búsqueda avanzada de productos
CREATE INDEX idx_productos_busqueda ON productos
USING gin(to_tsvector('spanish', nombre || ' ' || descripcion));
SELECT nombre, precio
FROM productos
WHERE to_tsvector('spanish', nombre || ' ' || descripcion) @@
to_tsquery('spanish', 'laptop & gaming');
Ventajas:
- Búsqueda full-text nativa
- Soporte para transacciones ACID
- Excelente para reportes complejos
- Integridad referencial garantizada
MongoDB: Catálogo Dinámico
// Productos con atributos dinámicos
db.productos.insertOne({
nombre: "Laptop Gaming Pro",
precio: 1499.99,
especificaciones: {
cpu: "Ryzen 9",
ram: "32GB",
almacenamiento: "1TB SSD"
},
variantes: [
{ color: "negro", stock: 10 },
{ color: "plata", stock: 5 }
],
tags: ["gaming", "laptop", "ryzen"]
})
// Búsqueda por especificaciones
db.productos.find({
"especificaciones.ram": "32GB",
tags: "gaming",
precio: { $lt: 1500 }
})
Ventajas:
- Esquema flexible
- Búsqueda por atributos dinámicos
- Mejor performance en lecturas
- Facilita cambios en el modelo de datos
Consideraciones de Performance
PostgreSQL: Optimización de Queries
-- Ejemplo de query optimizada con explicación
EXPLAIN ANALYZE
SELECT u.nombre, COUNT(o.id) as total_ordenes
FROM usuarios u
LEFT JOIN ordenes o ON u.id = o.usuario_id
WHERE u.created_at > NOW() - INTERVAL '30 days'
GROUP BY u.id, u.nombre;
Tips de optimización:
- Usa índices apropiados
- Analiza planes de ejecución
- Implementa particionamiento
- Mantén estadísticas actualizadas
MongoDB: Índices y Agregación
// Creación de índices estratégicos
db.usuarios.createIndex(
{ "email": 1 },
{ unique: true }
)
// Pipeline de agregación optimizado
db.ordenes.aggregate([
{ \$match: {
created_at: {
$gt: new Date(Date.now() - 30*24*60*60*1000)
}
}},
{ \$group: {
_id: "\$usuario_id",
total_ordenes: { $sum: 1 }
}},
{ $limit: 100 }
])
Consideraciones:
- Diseña índices eficientes
- Utiliza agregaciones en lugar de múltiples queries
- Implementa sharding cuando sea necesario
- Monitorea uso de memoria
Conclusiones y Recomendaciones
La elección entre PostgreSQL y MongoDB dependerá de:
- Naturaleza de tus datos
- Patrones de acceso
- Requisitos de consistencia
- Presupuesto disponible
Recursos Recomendados
Para profundizar en bases de datos, estos son los recursos que personalmente recomiendo:
Libros Esenciales
- “PostgreSQL: Up and Running” – Fundamental para entender PostgreSQL en profundidad
- “MongoDB: The Definitive Guide” – La mejor referencia para MongoDB