Conectar Node.js a una base de datos significa establecer un canal entre tu aplicación y un sistema que guarda información de forma permanente.
Cuando la memoria no es suficiente
Imagina que construiste una API para Liverpool. Cada vez que alguien agrega un producto al carrito, lo guardas en una variable de JavaScript. Todo funciona bien... hasta que reinicias el servidor. La variable desaparece. El carrito también. Esto le ha pasado a muchos developers principiantes.
Las variables en Node.js viven en la RAM. Son rápidas, pero temporales. Cuando el proceso termina, toda la información se borra. Necesitas un lugar donde los datos sobrevivan reinicios, errores y actualizaciones.
Ahí entra una base de datos.
El Sistema CONEXIÓN-MODELO-OPERACIÓN
Para trabajar con bases de datos en Node.js, vas a usar un sistema de tres pasos que se repite en cualquier proyecto real. Llámalo el Sistema CONEXIÓN-MODELO-OPERACIÓN.
- CONEXIÓN: Le dices a Node.js dónde está tu base de datos y cómo acceder a ella.
- MODELO: Defines la estructura de tus datos (como un formulario con campos específicos).
- OPERACIÓN: Guardas, consultas, actualizas o eliminas documentos usando ese modelo.
En esta lección usarás MongoDB como base de datos y Mongoose como la librería que conecta tu código con MongoDB. Mongoose es el puente.
Instalar Mongoose
Abres tu terminal en la carpeta del proyecto y ejecutas:
npm install mongoose
Eso es todo. Mongoose se agrega a tu package.json como dependencia.
Paso 1: Establecer la conexión
Antes de hacer cualquier operación, debes conectarte a la base de datos. Crea un archivo llamado db.js en la raíz de tu proyecto:
const mongoose = require('mongoose');
const conectarDB = async () => {
try {
await mongoose.connect('mongodb://localhost:27017/tienda_liverpool');
console.log('Base de datos conectada correctamente');
} catch (error) {
console.error('Error al conectar:', error.message);
process.exit(1);
}
};
module.exports = conectarDB;
Luego, en tu archivo principal index.js, importas y ejecutas esa función antes de iniciar el servidor:
const express = require('express');
const conectarDB = require('./db');
const app = express();
const PORT = 3000;
conectarDB();
app.use(express.json());
app.listen(PORT, () => {
console.log(`Servidor corriendo en el puerto ${PORT}`);
});
El orden importa: primero conectas la base de datos, después levantas el servidor.
Paso 2: Crear un modelo con Mongoose
Un modelo en Mongoose es un molde. Define exactamente qué campos tiene cada documento en tu colección.
Imagina que trabajas en el equipo de FEMSA y necesitas guardar información de sus productos. Crea una carpeta models y dentro un archivo Producto.js:
const mongoose = require('mongoose');
const productoSchema = new mongoose.Schema({
nombre: {
type: String,
required: true,
trim: true
},
precio: {
type: Number,
required: true,
min: 0
},
stock: {
type: Number,
default: 0
},
categoria: {
type: String,
enum: ['bebidas', 'snacks', 'lacteos', 'otros'],
default: 'otros'
},
creadoEn: {
type: Date,
default: Date.now
}
});
const Producto = mongoose.model('Producto', productoSchema);
module.exports = Producto;
Este schema dice: cada producto tiene un nombre (obligatorio), un precio (obligatorio), un stock que por defecto es 0, y una categoría de una lista permitida.
Paso 3: Las cuatro operaciones esenciales
Con el modelo listo, ya puedes ejecutar las operaciones básicas. Estas son las más comunes en cualquier API real.
Guardar un producto nuevo
const Producto = require('./models/Producto');
const guardarProducto = async () => {
const producto = new Producto({
nombre: 'Coca-Cola 600ml',
precio: 18500,
stock: 200,
categoria: 'bebidas'
});
const resultado = await producto.save();
console.log('Producto guardado:', resultado._id);
};
El campo precio usa 18500 como número entero en el código. Cuando lo muestres al usuario, formatea como $18,500.
Consultar todos los productos
const productos = await Producto.find();
console.log(`Total de productos: ${productos.length}`);
Buscar por filtro
const bebidas = await Producto.find({ categoria: 'bebidas' });
const productosBaratos = await Producto.find({ precio: { $lte: 50000 } });
Actualizar un producto
await Producto.findByIdAndUpdate(
'64abc123def456',
{ stock: 150 },
{ new: true }
);
El tercer argumento { new: true } hace que Mongoose te regrese el documento ya actualizado, no el anterior.
Eliminar un producto
await Producto.findByIdAndDelete('64abc123def456');
Integrando todo en una ruta de Express
Ahora conectas el modelo con las rutas que aprendiste en la lección anterior. Crea el archivo routes/productos.js:
const express = require('express');
const router = express.Router();
const Producto = require('../models/Producto');
// Obtener todos los productos
router.get('/', async (req, res) => {
try {
const productos = await Producto.find();
res.json(productos);
} catch (error) {
res.status(500).json({ error: 'Error al obtener productos' });
}
});
// Crear un producto
router.post('/', async (req, res) => {
try {
const producto = new Producto(req.body);
const nuevo = await producto.save();
res.status(201).json(nuevo);
} catch (error) {
res.status(400).json({ error: error.message });
}
});
// Obtener un producto por ID
router.get('/:id', async (req, res) => {
try {
const producto = await Producto.findById(req.params.id);
if (!producto) {
return res.status(404).json({ error: 'Producto no encontrado' });
}
res.json(producto);
} catch (error) {
res.status(500).json({ error: 'ID inválido o error del servidor' });
}
});
module.exports = router;
En tu index.js, registras esa ruta:
const productosRouter = require('./routes/productos');
app.use('/api/productos', productosRouter);
Ahora tienes una API con base de datos real en menos de 60 líneas.
Errores comunes al conectar bases de datos
Estos errores aparecen seguido en proyectos reales. Conocerlos te ahorra horas.
Error 1: No usar async/await en las operaciones
Mongoose devuelve promesas. Si no usas await, no esperas el resultado y recibes un objeto Promise vacío en lugar de tus datos.
Error 2: No manejar el error de conexión
Si MongoDB no está corriendo y no tienes un try/catch en tu conexión, el servidor se cae sin mensaje claro. Siempre usa process.exit(1) para detener la app con un mensaje de error visible.
Error 3: Olvidar validaciones en el schema
Si no marcas un campo como required: true, Mongoose acepta documentos incompletos. Imagina guardar un producto de Bimbo sin nombre ni precio. Tu base de datos queda con basura.
Error 4: Usar el mismo nombre para el modelo y la variable
Escribir const producto = mongoose.model('producto', ...) con minúscula confunde. Por convención, los modelos van en PascalCase: Producto, Usuario, Pedido.
Error 5: No formatear precios al mostrarlos
MongoDB guarda 18500 como número. Cuando lo envíes al frontend, el cliente debe formatearlo como $18,500. Si tu API mezcla lógica de presentación con lógica de datos, el código se complica innecesariamente.
Un ejemplo completo: API de pedidos para Mercado Libre
Piensa en un sistema de pedidos. Cada pedido tiene un comprador, una lista de productos y un total.
// models/Pedido.js
const pedidoSchema = new mongoose.Schema({
comprador: { type: String, required: true },
productos: [{ nombre: String, cantidad: Number, precioUnitario: Number }],
total: { type: Number, required: true },
estado: { type: String, enum: ['pendiente', 'enviado', 'entregado'], default: 'pendiente' },
fecha: { type: Date, default: Date.now }
});
Con este modelo puedes consultar todos los pedidos pendientes así:
const pendientes = await Pedido.find({ estado: 'pendiente' });
console.log(`Pedidos pendientes: ${pendientes.length}`);
O buscar pedidos con total mayor a $1,000:
const pedidosGrandes = await Pedido.find({ total: { $gt: 1000 } });
Ese patrón de filtros es el mismo para cualquier colección. Aprendes la sintaxis una vez y la reutilizas en todo el proyecto.
Variables de entorno para la URL de conexión
Nunca pongas la URL de tu base de datos directamente en el código. En equipos reales como el de FEMSA o Mercado Libre, cada desarrollador tiene su propia base de datos local y el servidor de producción tiene la suya.
Usa un archivo .env:
MONGO_URI=mongodb://localhost:27017/tienda_liverpool
Y en db.js:
require('dotenv').config();
await mongoose.connect(process.env.MONGO_URI);
Instala la dependencia con npm install dotenv y agrega .env a tu .gitignore. Así nunca subes credenciales a GitHub.
Cuando conectas tu API a una base de datos con el Sistema CONEXIÓN-MODELO-OPERACIÓN, dejas de construir demos y empiezas a construir productos reales.