Express
Tutorial Express: Conexión a MongoDB
Aprende a conectar MongoDB con Mongoose y definir esquemas robustos en Express 5 para aplicaciones Node.js profesionales.
Aprende Express y certifícateMongoose setup
Mongoose es el ODM (Object Document Mapper) más utilizado para trabajar con MongoDB en aplicaciones Node.js. A diferencia del driver nativo de MongoDB, Mongoose proporciona una capa de abstracción que incluye validación de esquemas, middleware y una sintaxis más intuitiva para las operaciones de base de datos.
Instalación de Mongoose
Para integrar Mongoose en tu aplicación Express 5, necesitas instalarlo como dependencia del proyecto:
npm install mongoose
Mongoose incluye internamente el driver de MongoDB, por lo que no necesitas instalar paquetes adicionales para la conectividad básica.
Configuración de la conexión
La configuración inicial de Mongoose requiere establecer la conexión con tu instancia de MongoDB. En Express 5, la mejor práctica es configurar esta conexión durante el arranque de la aplicación:
import express from 'express';
import mongoose from 'mongoose';
const app = express();
// Configuración de la conexión a MongoDB
const connectDB = async () => {
try {
await mongoose.connect('mongodb://localhost:27017/mi-aplicacion', {
// Opciones de conexión recomendadas
});
console.log('Conectado a MongoDB');
} catch (error) {
console.error('Error conectando a MongoDB:', error);
process.exit(1);
}
};
// Inicializar conexión
connectDB();
app.listen(3000, () => {
console.log('Servidor Express ejecutándose en puerto 3000');
});
Gestión de eventos de conexión
Mongoose emite eventos específicos que permiten monitorear el estado de la conexión. Configurar estos eventos proporciona mejor control sobre el comportamiento de tu aplicación:
import mongoose from 'mongoose';
// Evento de conexión exitosa
mongoose.connection.on('connected', () => {
console.log('Mongoose conectado a MongoDB');
});
// Evento de error de conexión
mongoose.connection.on('error', (error) => {
console.error('Error de conexión Mongoose:', error);
});
// Evento de desconexión
mongoose.connection.on('disconnected', () => {
console.log('Mongoose desconectado de MongoDB');
});
// Manejo de cierre graceful
process.on('SIGINT', async () => {
await mongoose.connection.close();
console.log('Conexión Mongoose cerrada por terminación de aplicación');
process.exit(0);
});
Configuración con variables de entorno
Para aplicaciones en producción, es fundamental externalizar la configuración de conexión utilizando variables de entorno:
import dotenv from 'dotenv';
import mongoose from 'mongoose';
dotenv.config();
const connectDB = async () => {
try {
const mongoURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/mi-aplicacion';
await mongoose.connect(mongoURI, {
maxPoolSize: 10, // Máximo de conexiones simultáneas
serverSelectionTimeoutMS: 5000, // Timeout para selección de servidor
socketTimeoutMS: 45000, // Timeout para operaciones de socket
});
console.log(`Conectado a MongoDB: ${mongoose.connection.host}`);
} catch (error) {
console.error('Fallo en conexión a MongoDB:', error.message);
process.exit(1);
}
};
Integración con Express 5
En Express 5, puedes modularizar la configuración de Mongoose creando un archivo dedicado para la configuración de base de datos:
config/database.js
:
import mongoose from 'mongoose';
class DatabaseConnection {
constructor() {
this.isConnected = false;
}
async connect() {
if (this.isConnected) {
console.log('Ya existe una conexión activa a MongoDB');
return;
}
try {
const connection = await mongoose.connect(process.env.MONGODB_URI);
this.isConnected = connection.connections[0].readyState === 1;
console.log('Base de datos conectada exitosamente');
} catch (error) {
console.error('Error en conexión a base de datos:', error);
throw error;
}
}
async disconnect() {
if (!this.isConnected) return;
await mongoose.disconnect();
this.isConnected = false;
console.log('Desconectado de MongoDB');
}
}
export default new DatabaseConnection();
app.js
:
import express from 'express';
import database from './config/database.js';
const app = express();
// Inicializar conexión a base de datos
const startServer = async () => {
try {
await database.connect();
app.listen(3000, () => {
console.log('Servidor Express 5 ejecutándose en puerto 3000');
});
} catch (error) {
console.error('Error iniciando servidor:', error);
process.exit(1);
}
};
startServer();
Configuración de opciones avanzadas
Mongoose permite personalizar el comportamiento de la conexión mediante diversas opciones que optimizan el rendimiento y la estabilidad:
const connectionOptions = {
// Pool de conexiones
maxPoolSize: 10,
minPoolSize: 5,
// Timeouts
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
connectTimeoutMS: 10000,
// Configuración de heartbeat
heartbeatFrequencyMS: 10000,
// Configuración de retry
retryWrites: true,
retryReads: true,
};
await mongoose.connect(mongoURI, connectionOptions);
Esta configuración establece las bases sólidas para trabajar con MongoDB en tu aplicación Express 5, proporcionando manejo robusto de errores, conexiones eficientes y una arquitectura escalable que facilita el mantenimiento del código.
Esquemas básicos
Los esquemas de Mongoose definen la estructura y las reglas de validación para los documentos que se almacenan en MongoDB. A diferencia de MongoDB que es una base de datos sin esquema, Mongoose introduce esta capa de tipado y validación que aporta consistencia y robustez a las aplicaciones Express.
Definición de esquemas
Un esquema en Mongoose se crea utilizando la clase Schema
y especifica los campos, tipos de datos y reglas de validación para una colección:
import mongoose from 'mongoose';
const { Schema } = mongoose;
// Definición básica de esquema
const usuarioSchema = new Schema({
nombre: String,
email: String,
edad: Number,
activo: Boolean,
fechaRegistro: Date
});
// Crear modelo a partir del esquema
const Usuario = mongoose.model('Usuario', usuarioSchema);
export default Usuario;
Tipos de datos fundamentales
Mongoose proporciona tipos de datos específicos que se mapean directamente con los tipos nativos de JavaScript y MongoDB:
const productoSchema = new Schema({
// Tipos primitivos
nombre: String,
precio: Number,
disponible: Boolean,
fechaCreacion: Date,
// Tipos especiales de Mongoose
id: mongoose.Schema.Types.ObjectId,
buffer: Buffer,
mixto: mongoose.Schema.Types.Mixed,
// Arrays
etiquetas: [String],
valoraciones: [Number],
// Objetos anidados
direccion: {
calle: String,
ciudad: String,
codigoPostal: String
}
});
Validaciones básicas
Los esquemas permiten definir reglas de validación que se ejecutan automáticamente antes de guardar documentos en la base de datos:
const clienteSchema = new Schema({
nombre: {
type: String,
required: true,
trim: true,
minlength: 2,
maxlength: 50
},
email: {
type: String,
required: [true, 'El email es obligatorio'],
unique: true,
lowercase: true,
match: [/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/, 'Email inválido']
},
edad: {
type: Number,
min: [18, 'Debe ser mayor de edad'],
max: [120, 'Edad no válida']
},
telefono: {
type: String,
validate: {
validator: function(v) {
return /\d{9}/.test(v);
},
message: 'El teléfono debe tener 9 dígitos'
}
}
});
Valores por defecto y transformaciones
Los esquemas pueden incluir valores predeterminados y funciones que se ejecutan automáticamente durante la creación o modificación de documentos:
const pedidoSchema = new Schema({
numero: {
type: String,
default: function() {
return 'PED-' + Date.now();
}
},
estado: {
type: String,
enum: ['pendiente', 'procesando', 'enviado', 'entregado'],
default: 'pendiente'
},
fechaCreacion: {
type: Date,
default: Date.now
},
total: {
type: Number,
required: true,
set: function(valor) {
return Math.round(valor * 100) / 100; // Redondear a 2 decimales
}
}
});
Uso de esquemas en rutas Express
Una vez definidos los esquemas, puedes utilizarlos en las rutas de Express para realizar operaciones CRUD:
import express from 'express';
import Usuario from '../models/Usuario.js';
const router = express.Router();
// Crear nuevo usuario
router.post('/usuarios', async (req, res) => {
try {
const nuevoUsuario = new Usuario(req.body);
const usuarioGuardado = await nuevoUsuario.save();
res.status(201).json(usuarioGuardado);
} catch (error) {
if (error.name === 'ValidationError') {
return res.status(400).json({
error: 'Datos inválidos',
detalles: error.message
});
}
res.status(500).json({ error: 'Error interno del servidor' });
}
});
// Obtener usuarios
router.get('/usuarios', async (req, res) => {
try {
const usuarios = await Usuario.find({ activo: true });
res.json(usuarios);
} catch (error) {
res.status(500).json({ error: 'Error al obtener usuarios' });
}
});
Esquemas con referencias
Los esquemas pueden establecer relaciones entre colecciones utilizando referencias a otros documentos:
const comentarioSchema = new Schema({
contenido: {
type: String,
required: true,
maxlength: 500
},
autor: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Usuario',
required: true
},
articulo: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Articulo',
required: true
},
fechaCreacion: {
type: Date,
default: Date.now
}
});
const Comentario = mongoose.model('Comentario', comentarioSchema);
Para utilizar estas referencias, puedes emplear el método populate()
que resuelve automáticamente las referencias:
// Obtener comentarios con información del autor
router.get('/comentarios', async (req, res) => {
try {
const comentarios = await Comentario
.find()
.populate('autor', 'nombre email')
.populate('articulo', 'titulo');
res.json(comentarios);
} catch (error) {
res.status(500).json({ error: 'Error al obtener comentarios' });
}
});
Organización de modelos
Para mantener una estructura ordenada en aplicaciones Express 5, organiza los esquemas en archivos separados dentro de una carpeta models
:
models/index.js
:
import Usuario from './Usuario.js';
import Producto from './Producto.js';
import Pedido from './Pedido.js';
export {
Usuario,
Producto,
Pedido
};
routes/api.js
:
import express from 'express';
import { Usuario, Producto, Pedido } from '../models/index.js';
const router = express.Router();
// Las rutas pueden acceder a todos los modelos
router.get('/dashboard', async (req, res) => {
try {
const stats = {
usuarios: await Usuario.countDocuments(),
productos: await Producto.countDocuments(),
pedidos: await Pedido.countDocuments()
};
res.json(stats);
} catch (error) {
res.status(500).json({ error: 'Error al obtener estadísticas' });
}
});
Los esquemas de Mongoose proporcionan una base sólida para estructurar los datos en aplicaciones Express, combinando la flexibilidad de MongoDB con las garantías de validación y consistencia que requieren las aplicaciones profesionales.
Otras lecciones de Express
Accede a todas las lecciones de Express y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Introducción A Expressjs
Introducción Y Entorno
Instalación De Express
Introducción Y Entorno
Estados Http
Routing
Métodos Delete
Routing
Parámetros Y Query Strings
Routing
Métodos Get
Routing
Ejercicios de programación de Express
Evalúa tus conocimientos de esta lección Conexión a MongoDB con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.