Database Integration
Database integration in Node.js involves connecting the application to a database to store, retrieve, and manage data.
This process is essential for creating dynamic applications that interact with data.
1. Choosing a Database
SQL Databases: Such as PostgreSQL and MySQL, use structured query language (SQL) for defining and manipulating data.
NoSQL Databases: Such as MongoDB and CouchDB, are designed for unstructured data and offer flexible schemas.
2. Connecting to a Database
For SQL Databases: Use libraries like pg for PostgreSQL or mysql2 for MySQL.
3. Performing CRUD Operations
Create: Insert new data into the database
Read: Query data from the database.
Update: Modify existing data.
Delete: Remove data from the database.
MySQL Database Setup
To integrate a MySQL database with Node.js application, you need to configure a connection pool, handle queries, and ensure proper table creation.
Setting Up the Database Connection
Use the mysql2/promise
library to create a connection pool that allows efficient handling of multiple database connections.
Database Connection Configuration:
import mysql from 'mysql2/promise';
const pool = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
connectionLimit: 10
});
console.log('MySQL Pool created successfully');
mysql.createPool(): Creates a pool of connections to the MySQL database.
connectionLimit: Specifies the maximum number of connections in the pool.
Query Execution Utility
Create a utility function for executing SQL queries. This function handles acquiring and releasing connections automatically.
Query Execution Function:
const query = async (sql, values) => {
const connection = await pool.getConnection();
try {
const [results] = await connection.query(sql, values);
return results;
} catch (err) {
return err;
} finally {
if (connection) {
connection.release();
}
}
};
export default query;
pool.getConnection(): Obtains a connection from the pool.
connection.query(): Executes the SQL query.
connection.release(): Releases the connection back to the pool.
Recipe Controller Functions
Implement controller functions for managing recipe data. These functions interact with the database using the query utility.
Recipe Controller Example:
import query from '../config/db.js';
const recipeControllers = {
getAllRecipes: async (req, res) => {
try {
const sql = 'SELECT * FROM recipes';
const recipes = await query(sql);
res.status(200).json(recipes);
} catch (error) {
console.error('Error fetching recipes:', error);
res.status(500).json({ error: 'Error fetching recipes' });
}
},
getRecipeByID: async (req, res) => {
const { id } = req.params;
try {
const sql = 'SELECT * FROM recipes WHERE id = ?';
const recipe = await query(sql, [id]);
if (recipe.length === 0) {
res.status(404).json({ error: 'Recipe not found' });
} else {
res.status(200).json(recipe[0]);
}
} catch (error) {
console.error('Error fetching recipe:', error);
res.status(500).json({ error: 'Error fetching recipe' });
}
},
getRecipesByName: async (req, res) => {
const { q } = req.query;
try {
if (!q) {
return await recipeControllers.getAllRecipes(req, res);
}
const sql = 'SELECT * FROM recipes WHERE name LIKE ?';
const searchTerm = `%${q}%`;
const recipes = await query(sql, [searchTerm]);
if (recipes.length === 0) {
res.status(404).json({ error: 'Recipe not found' });
} else {
res.status(200).json(recipes);
}
} catch (error) {
console.error('Error fetching recipes by name:', error);
res.status(500).json({ error: 'Error fetching recipes by name' });
}
},
postRecipe: async (req, res) => {
const { name, description } = req.body;
try {
if (!name) {
return res.status(400).json({ error: 'Name of the recipe is required' });
}
const sql = 'INSERT INTO recipes (name, description) VALUES(?, ?)';
const values = [name, description || null];
const result = await query(sql, values);
const insertedRecipeId = result.insertId;
const fetchSql = 'SELECT * FROM recipes WHERE id = ?';
const newRecipe = await query(fetchSql, [insertedRecipeId]);
res.status(201).json({
recipe: newRecipe[0],
message: `"${newRecipe[0].name}" Recipe is added successfully`,
result: result
});
} catch (error) {
console.error('Error adding recipe:', error);
res.status(500).json({ error: 'Error adding recipe' });
}
},
updateRecipe: async (req, res) => {
const { id } = req.params;
const { name, description } = req.body;
try {
if (!name && !description) {
return res.status(400).json({ error: 'At least one field (name or description) is required to update' });
}
let sql = 'UPDATE recipes SET ';
const values = [];
if (name) {
sql += 'name = ?, ';
values.push(name);
}
if (description) {
sql += 'description = ?, ';
values.push(description);
}
sql = sql.slice(0, -2);
sql += ' WHERE id = ?';
values.push(id);
const result = await query(sql, values);
if (result.affectedRows === 0) {
return res.status(404).json({ error: 'Recipe not found' });
}
const fetchSql = 'SELECT * FROM recipes WHERE id = ?';
const updatedRecipe = await query(fetchSql, [id]);
res.status(200).json({ recipe: updatedRecipe[0], message: 'Recipe updated successfully', result: result });
} catch (error) {
console.error('Error updating recipe:', error);
res.status(500).json({ error: 'Error updating recipe' });
}
},
deleteRecipe: async (req, res) => {
const { id } = req.params;
try {
const sql = 'SELECT * FROM recipes WHERE id = ?';
const selectRecipe = await query(sql, [id]);
if (selectRecipe.length === 0) {
return res.status(404).json({ error: 'Recipe not found' });
}
const deleteSql = 'DELETE FROM recipes WHERE id = ?';
const result = await query(deleteSql, [id]);
res.status(200).json({ message: `"${selectRecipe[0].name}" is deleted successfully`, recipeId: id, result: result });
} catch (error) {
console.error('Error deleting recipe:', error);
res.status(500).json({ error: 'Error deleting recipe' });
}
}
};
export default recipeControllers;
Table Creation Script
Create the necessary database table using a script that ensures the table is created if it doesn’t already exist.
Table Creation Script:
import query from '../config/db.js';
const createRecipeTable = async () => {
const sql = `
CREATE TABLE IF NOT EXISTS recipes (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
`;
try {
await query(sql);
} catch (error) {
console.error('Error creating recipes table:', error);
}
};
export default createRecipeTable;
Table Definition:
id: Auto-increment primary key.
name: Non-nullable field for the recipe name
description: Optional field for additional details.
created_at & updated_at: Timestamps for record creation and last update.
This section demonstrates how to integrate MySQL with a Node.js application by configuring a connection pool, executing queries, and managing recipe data.
Last updated