¿Por qué JavaScript se lleva bien con PostgreSQL?
\n\nSi escribes en JavaScript (especialmente en Node.js) y todavía usas MySQL o, Dios no lo quiera, SQLite en producción, estás perdiendo dinero y paciencia. PostgreSQL no es solo "otra base de datos". Es una navaja suiza para datos que lo sabe hacer todo: desde JOIN complejos hasta documentos JSON, búsqueda de texto completo y consultas geoespaciales. Y la combinación JavaScript + PostgreSQL es el estándar moderno para aplicaciones web, microservicios y análisis.
\n\nEn esta guía analizaremos todo lo que necesita saber un desarrollador de Node.js: desde la instalación del controlador hasta transacciones, migraciones y optimización. Sin rodeos: solo código y práctica.
\n\nPaso 1: Instalación y configuración del controlador pg
\n\nPara trabajar con PostgreSQL desde JavaScript se utiliza el paquete pg, el cliente oficial. Se instala en un segundo:
npm install pg\n\nAhora creamos la conexión. Hay dos enfoques: Client (una sola conexión) y Pool (grupo de conexiones). Para producción, use siempre Pool: gestiona la reutilización de conexiones y no satura la base de datos bajo carga.
\n\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n user: 'tu_usuario',\n host: 'localhost',\n database: 'tu_bd',\n password: 'tu_contraseña',\n port: 5432,\n max: 20, // máx. conexiones en el pool\n idleTimeoutMillis: 30000,\n connectionTimeoutMillis: 2000,\n});\n\n// Prueba de conexión\npool.query('SELECT NOW()')\n .then(res => console.log('✅ Conectado:', res.rows[0].now))\n .catch(err => console.error('❌ Error:', err));\n\nImportante: Nunca codifique las contraseñas. Use variables de entorno (process.env.DATABASE_URL) o un gestor de secretos.
Paso 2: CRUD — la base de todo
\n\nCualquier aplicación comienza con CRUD (Create, Read, Update, Delete). Analicemos cada operación en JavaScript con PostgreSQL.
\n\nCreación de tabla (DDL)
\n\nconst createTable = async () => {\n const query = `\n CREATE TABLE IF NOT EXISTS users (\n id SERIAL PRIMARY KEY,\n name VARCHAR(100) NOT NULL,\n email VARCHAR(255) UNIQUE NOT NULL,\n age INTEGER CHECK (age > 0),\n created_at TIMESTAMP DEFAULT NOW()\n );\n `;\n await pool.query(query);\n console.log('✅ Tabla users creada');\n};\n\ncreateTable();\n\nINSERT — agregar datos
\n\nconst addUser = async (name, email, age) => {\n // Usamos consulta parametrizada — ¡protección contra inyección SQL!\n const query = `\n INSERT INTO users (name, email, age)\n VALUES ($1, $2, $3)\n RETURNING *;\n `;\n const values = [name, email, age];\n const res = await pool.query(query, values);\n console.log('✅ Usuario agregado:', res.rows[0]);\n return res.rows[0];\n};\n\n// Ejemplo de llamada\naddUser('Ana Petrova', 'anna@example.com', 28);\n\nSELECT — lectura con filtrado
\n\nconst getUsers = async (minAge = 0) => {\n const query = 'SELECT * FROM users WHERE age > $1 ORDER BY created_at DESC';\n const res = await pool.query(query, [minAge]);\n console.log(`📊 Usuarios encontrados: ${res.rowCount}`);\n return res.rows;\n};\n\ngetUsers(25).then(users => console.log(users));\n\nUPDATE — actualizar registro
\n\nconst updateUserEmail = async (id, newEmail) => {\n const query = `\n UPDATE users\n SET email = $2, updated_at = NOW()\n WHERE id = $1\n RETURNING *;\n `;\n const res = await pool.query(query, [id, newEmail]);\n if (res.rowCount === 0) {\n console.log('⚠️ Usuario no encontrado');\n return null;\n }\n console.log('✅ Email actualizado:', res.rows[0]);\n return res.rows[0];\n};\n\nDELETE — eliminación
\n\nconst deleteUser = async (id) => {\n const query = 'DELETE FROM users WHERE id = $1 RETURNING *';\n