Skip to main content
backend30 de noviembre de 202514 min de lectura

Elegir la Base de Datos Correcta: Relacional vs NoSQL para Proyectos Reales

Un marco de decisión práctico para elegir entre PostgreSQL, MongoDB, Firebase, Redis y otras bases de datos según tus requisitos reales.

databasepostgresqlmongodb
Elegir la Base de Datos Correcta: Relacional vs NoSQL para Proyectos Reales

"Depende" es la respuesta honesta a toda pregunta sobre bases de datos, pero también es inútil. Cuando estás comenzando un proyecto y necesitas elegir una base de datos, necesitas algo más concreto que una lista de compensaciones. Necesitas un marco de decisión que considere tus requisitos reales — la forma de los datos, los patrones de consulta, la experiencia del equipo, las expectativas de escalado y la complejidad operativa.

He usado PostgreSQL, MongoDB, Firebase/Firestore, Redis y SQLite en distintos proyectos en producción. Cada elección fue correcta para su contexto, y algunas estuvieron equivocadas y tuvieron que migrarse. Los patrones detrás de esas decisiones son más útiles que cualquier comparación de benchmarks.

El Marco de Decisión

Antes de analizar bases de datos individuales, responde estas cinco preguntas sobre tu proyecto:

1. ¿Qué forma tienen tus datos?

No se trata de "relacional vs documento." Se trata de cómo se relacionan tus entidades de datos entre sí.

Altamente relacional: Los usuarios tienen pedidos, los pedidos tienen artículos, los artículos pertenecen a categorías, las categorías tienen jerarquías. Si dibujas tu modelo de datos y parece un grafo con muchas conexiones, necesitas capacidades relacionales sólidas.

Orientado a documentos: Cada entidad es relativamente autónoma. Un artículo de blog contiene su título, cuerpo, etiquetas e información del autor. Rara vez necesitas hacer joins entre tipos de entidades.

Clave-valor: Necesitas almacenar y recuperar por clave. Datos de sesión, configuración, feature flags.

Series temporales: Eventos, métricas, logs. Escritura intensiva, solo agregar, consultado por rango de tiempo.

2. ¿Cuáles son tus patrones de consulta?

Consultas conocidas: Sabes exactamente qué consultas ejecutará la aplicación. E-commerce: "obtener los pedidos del usuario," "buscar productos por categoría," "calcular el ingreso total de este mes." Las consultas conocidas favorecen las bases de datos relacionales donde puedes optimizar con índices y planes de consulta.

Consultas ad-hoc: Los usuarios pueden buscar, filtrar y agregar de maneras impredecibles. Dashboards analíticos, funciones de búsqueda, herramientas de reportes. Estas favorecen motores de consulta flexibles.

Búsquedas simples: La mayoría de lecturas son "obtener documento por ID." Las bases de datos documentales y los almacenes clave-valor sobresalen aquí.

3. ¿Cuál es tu requisito de consistencia?

Consistencia fuerte: Banca, inventario, cualquier cosa donde leer datos desactualizados cause problemas reales. Las bases de datos relacionales con transacciones ACID son la opción segura.

Consistencia eventual: Feeds sociales, analítica, caché. Puedes tolerar leer datos ligeramente desactualizados a cambio de rendimiento y disponibilidad.

4. ¿Cuál es tu trayectoria de escalado?

El escalado vertical está bien: La mayoría de las aplicaciones. Si tu base de datos cabe en una sola máquina con espacio para crecer, cualquier base de datos funciona. PostgreSQL en un servidor moderno maneja millones de filas sin despeinarse.

Se necesita escalado horizontal: Necesitas distribuir datos entre múltiples máquinas. Esto es más raro de lo que la mayoría de los desarrolladores piensan, pero cuando lo necesitas, tu elección de base de datos está limitada.

5. ¿Qué sabe tu equipo?

Este factor está subestimado. Un equipo de expertos en PostgreSQL será más productivo con PostgreSQL, incluso si MongoDB es teóricamente una mejor opción para el modelo de datos. El costo de aprender una nueva base de datos — depurar errores desconocidos, aprender mejores prácticas operativas, entender las características de rendimiento — es real y significativo.

PostgreSQL: La Opción por Defecto

Si no estás seguro, elige PostgreSQL. Esta no es una opinión controvertida entre ingenieros de backend — es el consenso. PostgreSQL maneja datos relacionales, documentos JSON, búsqueda de texto completo, consultas geoespaciales y datos de series temporales. No es el mejor en ninguna de estas, pero es suficientemente bueno en todas para servir como base de datos única para la mayoría de las aplicaciones.

Fortalezas

Transacciones ACID. Cuando necesitas actualizar múltiples tablas atómicamente — descontar inventario y crear un pedido, transferir dinero entre cuentas — PostgreSQL garantiza la corrección.

Capacidades de consulta ricas. Funciones de ventana, CTEs (Common Table Expressions), consultas recursivas, lateral joins. SQL no es solo SELECT * FROM — es un lenguaje de consulta potente que puede expresar analítica compleja sin mover datos a una capa de aplicación.

-- Encontrar el pedido más reciente de cada usuario con total acumulado
WITH ranked_orders AS (
  SELECT
    user_id,
    order_id,
    total,
    created_at,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) as rn,
    SUM(total) OVER (PARTITION BY user_id ORDER BY created_at) as running_total
  FROM orders
)
SELECT * FROM ranked_orders WHERE rn = 1;

Columnas JSONB. Cuando parte de tus datos son genuinamente sin esquema — preferencias de usuario, respuestas de formularios dinámicos, payloads de webhooks de terceros — puedes almacenarlos como JSONB y consultarlos con soporte completo de indexación.

-- Almacenar y consultar datos semi-estructurados
CREATE TABLE products (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  attributes JSONB DEFAULT '{}'
);

-- Indexar una ruta JSON específica
CREATE INDEX idx_products_color ON products USING GIN ((attributes->'color'));

-- Consultar datos JSON
SELECT name FROM products
WHERE attributes->>'color' = 'blue'
AND (attributes->>'weight')::numeric < 10;

Ecosistema de extensiones. PostGIS para geoespacial, pg_trgm para búsqueda de texto difusa, TimescaleDB para series temporales, pgvector para embeddings de IA. El modelo de extensiones significa que PostgreSQL puede adaptarse a cargas de trabajo especializadas sin reemplazar tu base de datos principal.

Cuándo PostgreSQL No Es la Opción Correcta

  • Rendimiento masivo de escritura con escalado horizontal. PostgreSQL escala verticalmente bien (máquina más grande) pero el sharding horizontal es complejo. Si necesitas escribir millones de eventos por segundo a través de docenas de máquinas, considera soluciones especializadas.
  • Prototipado rápido donde los cambios de esquema ocurren diariamente. Durante las etapas más tempranas de una startup cuando el modelo de datos cambia fundamentalmente cada semana, la sobrecarga de las migraciones puede ralentizarte comparado con opciones sin esquema.
  • Cuando tu equipo tiene cero experiencia en SQL y el cronograma del proyecto no permite aprender. Esto es raro, pero sucede.

MongoDB: Cuando los Documentos Tienen Sentido

MongoDB recibe más críticas de las que merece. El marketing inicial ("¡sin esquema! ¡escala web!") creó expectativas poco realistas, y muchos desarrolladores lo usaron para casos donde PostgreSQL habría sido mejor. Pero hay escenarios genuinos donde MongoDB es la opción correcta.

Cuándo MongoDB Gana

Sistemas de gestión de contenido. Cada pieza de contenido tiene una estructura diferente — los artículos tienen campos diferentes a los videos, que tienen campos diferentes a los podcasts. En MongoDB, todos son documentos en la misma colección con diferentes formas. En PostgreSQL, o creas una tabla ancha con muchas columnas nullable, usas columnas JSON (en cuyo caso estás usando el paradigma de MongoDB en PostgreSQL), o creas una tabla por tipo con joins complejos.

Event sourcing y logging. Alto rendimiento de escritura con documentos que se escriben y leen mayormente, rara vez se actualizan y nunca se hacen join.

Los documentos embebidos reducen los joins. Si un pedido siempre necesita sus artículos, y los artículos nunca se acceden sin su pedido, embeber los artículos dentro del documento del pedido significa que tu consulta más común es una búsqueda de un solo documento en lugar de un join entre dos tablas.

// Documento MongoDB con sub-documentos embebidos
{
  _id: ObjectId("..."),
  customer: {
    name: "John Doe",
    email: "john@example.com"
  },
  items: [
    { product: "Widget", quantity: 2, price: 9.99 },
    { product: "Gadget", quantity: 1, price: 24.99 }
  ],
  total: 44.97,
  status: "shipped",
  createdAt: ISODate("2026-03-01T10:00:00Z")
}

El escalado horizontal es una característica de primera clase. El sharding de MongoDB está integrado y bien documentado. Si genuinamente necesitas distribuir datos entre muchos nodos (cientos de millones de documentos con alto rendimiento), MongoDB maneja esto con más gracia que PostgreSQL.

Cuándo MongoDB Está Mal

  • Datos altamente relacionales. Si estás escribiendo agregaciones $lookup (la versión de MongoDB de los joins) en cada consulta, elegiste la base de datos equivocada.
  • Cuando necesitas transacciones entre colecciones frecuentemente. MongoDB soporta transacciones multi-documento, pero añaden latencia y complejidad. Si tus operaciones principales requieren atomicidad entre colecciones, el modelo de transacciones de PostgreSQL es más natural.
  • Cuando realmente necesitas un esquema. "Sin esquema" suena liberador hasta que te das cuenta de que cada pieza de código que lee de la base de datos es implícitamente un esquema. Sin un esquema aplicado por la base de datos, mueves la validación a la capa de aplicación, donde es más fácil equivocarse y más difícil de aplicar consistentemente.

Firebase y Firestore: Desarrollo Rápido

Firebase Realtime Database y Firestore sirven un nicho específico: aplicaciones donde la velocidad de desarrollo importa más que la pureza del modelo de datos, y donde el backend es principalmente una capa de persistencia y sincronización de datos en lugar de un motor de lógica de negocio compleja.

Cuándo Firebase Brilla

Apps mobile-first con sincronización en tiempo real. Los SDKs de Firebase manejan caché offline, listeners en tiempo real y resolución de conflictos de forma nativa. Construir esto desde cero con PostgreSQL requiere una capa de WebSocket, una estrategia de caché y código personalizado significativo.

Equipos pequeños sin ingenieros de backend. Firebase elimina la necesidad de gestionar un servidor de base de datos, construir una capa API, implementar autenticación y manejar almacenamiento de archivos. Para un equipo de dos personas construyendo un MVP, esta reducción en sobrecarga operativa puede ser la diferencia entre lanzar y no lanzar.

Prototipado y validación. Cuando necesitas probar una idea con usuarios reales en dos semanas, Firebase te permite enfocarte completamente en la aplicación cliente. Si la idea se valida, puedes migrar a un backend más tradicional después.

Limitaciones de Firebase

Restricciones de consulta en Firestore. No puedes consultar campos que no están indexados. No puedes hacer filtros de desigualdad en múltiples campos. No puedes hacer búsqueda de texto completo. Estas limitaciones te obligan a desnormalizar agresivamente y a veces duplicar datos entre colecciones.

// Firestore: NO puedes hacer esto
db.collection('products')
  .where('price', '>', 10)
  .where('rating', '>', 4)
  .orderBy('name')  // Error: necesita índice compuesto en price + rating + name

// Firestore: SÍ puedes hacer esto (con un índice compuesto)
db.collection('products')
  .where('price', '>', 10)
  .where('rating', '>', 4)
  .orderBy('price')  // Debe ordenar por un campo usado en desigualdad

Dependencia del proveedor. Tu modelo de datos, reglas de seguridad y patrones de consulta son todos específicos de Firebase. Migrar desde Firebase es una reescritura, no una migración.

Imprevisibilidad de costos. Firebase cobra por lectura/escritura de documentos. Una consulta mal optimizada o un listener en tiempo real en una colección grande puede generar facturas sorprendentes. He visto proyectos donde un solo listener mal configurado costó más que un servidor dedicado de PostgreSQL por un año.

Lógica del lado del servidor limitada. Cloud Functions puede manejar algo de procesamiento del lado del servidor, pero lógica de negocio compleja — transacciones de múltiples pasos, agregación de datos, procesamiento en segundo plano — requiere soluciones creativas o un backend separado de todos modos.

Decisión: Firebase vs Backend Tradicional

Factor Firebase PostgreSQL + API
Tiempo al MVP Días Semanas
Sobrecarga operativa Casi cero Moderada
Flexibilidad de consultas Limitada SQL completo
Costo a escala Impredecible Predecible
Dependencia del proveedor Alta Baja
Soporte offline Integrado Hay que construirlo
Lógica de negocio compleja Difícil Natural
Equipo requerido Solo frontend Frontend + Backend

Redis: Caché, Colas y Más

Redis no es una base de datos principal para la mayoría de las aplicaciones (aunque Redis con módulos de persistencia puede cumplir ese rol). Es un almacén de estructuras de datos de alto rendimiento que sobresale en problemas específicos.

Caché

El caso de uso más común de Redis. Cachear consultas costosas a la base de datos, respuestas de API o resultados calculados.

import redis
import json

r = redis.Redis(host='localhost', port=6379, db=0)

def get_user_profile(user_id: str):
    # Verificar caché primero
    cached = r.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)

    # Cache miss — consultar base de datos
    profile = db.query("SELECT * FROM users WHERE id = %s", user_id)

    # Cachear por 5 minutos
    r.setex(f"user:{user_id}", 300, json.dumps(profile))
    return profile

Almacenamiento de Sesiones

El modelo clave-valor de Redis con soporte TTL (time-to-live) es una opción natural para datos de sesión. Es más rápido que las sesiones respaldadas por base de datos y más simple que las soluciones basadas en JWT para aplicaciones con estado.

Limitación de Tasa

def is_rate_limited(user_id: str, limit: int = 100, window: int = 60) -> bool:
    key = f"rate:{user_id}"
    current = r.incr(key)
    if current == 1:
        r.expire(key, window)
    return current > limit

Colas de Trabajo

Las listas y streams de Redis son excelentes colas de trabajo. Bibliotecas como Bull (Node.js), Celery (Python) y Sidekiq (Ruby) usan Redis como su broker de mensajes.

Cuándo No Usar Redis

  • Como tu única base de datos. Redis es en memoria por defecto. Incluso con persistencia (snapshots RDB o logs AOF), no está diseñado para datos que no puedes permitirte perder.
  • Para consultas complejas. Las estructuras de datos de Redis (strings, listas, sets, sorted sets, hashes) son poderosas pero no consultables como una base de datos. Accedes a datos por clave, no por condiciones arbitrarias.
  • Cuando no tienes un problema de caché. Agregar Redis a un stack que no necesita caché añade complejidad operativa sin beneficio. Una consulta PostgreSQL que toma 5ms no necesita ser cacheada.

Usar Múltiples Bases de Datos

La mayoría de las aplicaciones en producción de complejidad moderada usan más de una base de datos. La clave es usar cada una para lo que hace mejor, no intentar forzar una base de datos para manejar todo.

Un patrón común para una aplicación web:

  • PostgreSQL para datos de negocio principales (usuarios, pedidos, productos).
  • Redis para caché, sesiones y limitación de tasa.
  • S3 (o equivalente) para almacenamiento de archivos (imágenes, documentos, backups).

Para una aplicación en tiempo real:

  • PostgreSQL para datos persistentes y consultas complejas.
  • Redis para pub/sub y caché.
  • Firebase/Supabase para sincronización en tiempo real con clientes móviles.

El Patrón de Integración

Cuando usas múltiples bases de datos, establece una propiedad clara. Cada pieza de datos tiene una fuente autoritativa, y los otros sistemas son cachés o vistas de esos datos.

PostgreSQL (fuente de verdad)
    ├── Redis (caché de lectura, expira después de TTL)
    ├── Elasticsearch (índice de búsqueda, sincronizado via change data capture)
    └── Firebase (sincronización móvil, actualizado via webhooks)

Nunca tengas dos bases de datos que ambas se consideren propietarias de los mismos datos. Ese camino lleva a pesadillas de consistencia que son casi imposibles de depurar.

Consideraciones de Migración

Si te das cuenta de que elegiste la base de datos equivocada, la migración es posible pero costosa. Aquí están las consideraciones prácticas:

MongoDB a PostgreSQL es la migración más común que he visto. La razón habitual es que la aplicación creció más allá de las consultas documentales y necesitaba joins complejos, transacciones o agregaciones. La migración implica diseñar un esquema relacional, escribir scripts de transformación y actualizar cada consulta de base de datos en la aplicación. Calcula de dos a cuatro semanas para una aplicación moderadamente compleja.

PostgreSQL a MongoDB es más raro pero ocurre cuando el modelo de datos de una aplicación se vuelve predominantemente orientado a documentos. La migración es mecánicamente más simple (aplanar tablas en documentos) pero requiere repensar cada consulta y perder las garantías transaccionales.

Firebase a PostgreSQL es la migración más difícil porque no es solo un cambio de base de datos — es un cambio de arquitectura. Necesitas construir una capa API, implementar autenticación, reemplazar listeners en tiempo real con WebSockets o polling, y manejar la sincronización offline. Esto está más cerca de una reescritura que de una migración.

La mejor migración es la que evitas. Dedica un día extra a pensar en tu modelo de datos por adelantado. Habla con alguien que haya construido una aplicación similar. El costo de elegir la base de datos correcta inicialmente es siempre menor que el costo de migrar después.

Análisis de Costos

Los costos de bases de datos a escala pueden ser sorprendentes, especialmente con servicios gestionados.

Servicio Tier Gratuito Producción Pequeña Producción Media
Supabase (PostgreSQL) 500MB, 2 proyectos ~$25/mes (8GB, 2 cores) ~$100/mes (32GB, 4 cores)
Neon (PostgreSQL) 0.5GB almacenamiento ~$19/mes ~$69/mes
MongoDB Atlas 512MB compartido ~$57/mes (M10 dedicado) ~$200/mes (M30)
Firebase Firestore 1GB almacenamiento, 50k lecturas/día ~$25-100/mes (varía ampliamente) $100-1000/mes (depende de consultas)
Redis Cloud 30MB ~$7/mes (250MB) ~$60/mes (1GB)
PlanetScale (MySQL) 5GB, 1B lecturas de filas/mes ~$39/mes ~$99/mes

La imprevisibilidad de costos de Firebase merece énfasis. He visto proyectos donde los costos se mantuvieron por debajo de $30/mes durante meses, luego se dispararon a $300 después de un lanzamiento de función que aumentó las lecturas de documentos. Con PostgreSQL o MongoDB, los costos se correlacionan con el tamaño de la máquina, lo cual es predecible.

Mi Proceso de Decisión Real

Cuando comienzo un nuevo proyecto, la decisión generalmente va así:

  1. Por defecto PostgreSQL a menos que haya una razón específica para no hacerlo.
  2. Agregar Redis si la aplicación tiene necesidades de caché, limitación de tasa o colas de trabajo.
  3. Considerar Firebase/Supabase si la aplicación es mobile-first con requisitos de tiempo real y el equipo es pequeño.
  4. Considerar MongoDB si el modelo de datos es genuinamente orientado a documentos con requisitos relacionales mínimos.
  5. Agregar bases de datos especializadas (Elasticsearch, TimescaleDB, etc.) solo cuando una carga de trabajo específica lo demande.

Este marco me ha servido bien en una variedad de proyectos, desde plataformas de gestión de restaurantes hasta aplicaciones de salud móviles. La idea clave es que la base de datos es infraestructura — debe servir las necesidades de tu aplicación, no dictar tu arquitectura. Elige la opción aburrida que funciona, y dedica tu esfuerzo de ingeniería a las partes de la aplicación que te diferencian.

DU

Danil Ulmashev

Full Stack Developer

Interesado en trabajar juntos?