ЗВІТИ З ЛАБОРАТОРНИХ РОБІТ

з дисципліни «WEB-ОРІЄНТОВАНІ ТЕХНОЛОГІЇ. BACKEND РОЗРОБКИ»
Виконавець: Студент групи ІК-33 — Вересоцький Арсеній Юрійович
Arsenii Veresotskyi

ЗВІТ З ЛАБОРАТОРНОЇ РОБОТИ № 2

Тема: Створення бази даних у MySQL. Підключення Node.js до MySQL. Робота з ORM Sequelize

Виконав: Вересоцький Арсеній Група: ІК-33

1 СТВОРЕННЯ БАЗИ ДАНИХ ТА ВИКОНАННЯ SQL-ЗАПИТІВ

1.1 Проєктування бази даних

Для системи “Library of Things” (Бібліотека Речей) було спроєктовано базу даних library_of_things_db. На даному етапі створено дві основні таблиці, які пов’язані відношенням One-to-Many (Один-до-багатьох):

  1. users (Користувачі) — власники речей.
  2. items (Речі) — предмети, які користувачі здають в оренду.

1.2 Виконання базових SQL-запитів

Для перевірки роботи MySQL сервера було виконано наступні DDL та DML запити безпосередньо в СУБД (наприклад, через DBeaver).

Створення бази даних та таблиць:

CREATE DATABASE library_of_things_db;
USE library_of_things_db;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL UNIQUE,
    createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

CREATE TABLE items (
    id INT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    userId INT,
    createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
);

CRUD операції (INSERT, SELECT, UPDATE, DELETE):

-- INSERT: Додавання користувачів та речей
INSERT INTO users (name, email) VALUES ('Арсеній Вересоцький', 'arseniy@gmail.com');
INSERT INTO users (name, email) VALUES ('Іван Франко', 'ivan@lot.ua');

INSERT INTO items (title, description, userId) 
VALUES ('Дриль ударний', 'Потужний дриль для домашніх робіт', 1);
INSERT INTO items (title, description, userId) 
VALUES ('Намет 2-місний', 'Легкий туристичний намет', 1);

-- SELECT: Отримання всіх речей з інформацією про власника (JOIN)
SELECT items.title, items.description, users.name as owner 
FROM items 
JOIN users ON items.userId = users.id;

-- UPDATE: Оновлення опису речі
UPDATE items SET description = 'Оновлений опис: Намет туристичний (синій)' WHERE id = 2;

-- DELETE: Видалення запису
DELETE FROM items WHERE id = 2;

Скрін 1

2 ПІДКЛЮЧЕННЯ NODE.JS ДО MYSQL (ДРАЙВЕР MYSQL2)

Наступним кроком було підключення створеного у ЛР №1 Node.js проєкту до бази даних MySQL. Для цього встановлено пакет mysql2.

npm install mysql2

Тестове підключення та виконання SQL-запиту через Node.js

// файл raw-db-test.js
const mysql = require('mysql2/promise');

async function testRawConnection() {
    try {
        const connection = await mysql.createConnection({
            host: 'localhost',
            user: 'root',
            password: '',
            database: 'library_of_things_db'
        });

        console.log('Успішне підключення до MySQL через mysql2!');

        // Виконання підготовленого (Prepared) запиту
        const [rows] = await connection.execute('SELECT * FROM users WHERE id = ?', [1]);
        console.log('Знайдений користувач:', rows);

        await connection.end();
    } catch (error) {
        console.error('Помилка підключення:', error);
    }
}

testRawConnection();

Скрін 2

3 ВИКОРИСТАННЯ ORM SEQUELIZE

Для спрощення роботи з базою даних та заміни “сирих” SQL запитів на роботу з об’єктами JavaScript, у проєкт було інтегровано ORM Sequelize.

npm install sequelize

3.1 Файлова структура проєкту (оновлена)

Було створено нові директорії для конфігурації та моделей:

/lab1-rest-api
├── /config
│   └── database.js      # Налаштування підключення Sequelize
├── /models
│   ├── User.js          # Модель Користувача
│   └── Item.js          # Модель Речі
├── server.js            # Головний файл сервера (REST API)
├── package.json
└── README.md

3.2 Налаштування підключення (config/database.js)

const { Sequelize } = require('sequelize');

const sequelize = new Sequelize(
    'library_of_things_db', // Назва бази даних
    'root',                 // Користувач
    '',        // Пароль
    {
        host: 'localhost',
        dialect: 'mysql',
        logging: false      // Вимикаємо вивід SQL запитів у консоль (опціонально)
    }
);

module.exports = sequelize;

3.3 Створення моделей та зв’язків

Модель User (models/User.js):

const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');

const User = sequelize.define('User', {
    name: {
        type: DataTypes.STRING,
        allowNull: false
    },
    email: {
        type: DataTypes.STRING,
        allowNull: false,
        unique: true
    }
});

module.exports = User;

Модель Item (models/Item.js):

const { DataTypes } = require('sequelize');
const sequelize = require('../config/database');

const Item = sequelize.define('Item', {
    title: {
        type: DataTypes.STRING,
        allowNull: false
    },
    description: {
        type: DataTypes.TEXT,
        allowNull: false
    }
});

module.exports = Item;

Ініціалізація зв’язку One-to-Many у server.js:

У головному файлі сервера моделі було пов’язано між собою. User може мати багато Item, а Item належить одному User.

// Фрагмент server.js
const sequelize = require('./config/database');
const User = require('./models/User');
const Item = require('./models/Item');

// Реалізація зв'язку One-to-Many
User.hasMany(Item, { foreignKey: 'userId' });
Item.belongsTo(User, { foreignKey: 'userId' });

// Синхронізація бази даних
sequelize.sync({ alter: true }) // alter: true оновлює таблиці без їх видалення
    .then(() => {
        console.log("Таблиці успішно синхронізовані з БД.");
    })
    .catch(err => console.log("Помилка синхронізації: ", err));

3.4 Реалізація REST API за допомогою Sequelize

Логіку роботи з масивом у пам’яті (з ЛР №1) було повністю замінено на запити до бази даних через методи Sequelize (findAll, findByPk, create, update, destroy).

Приклад маршрутів (CRUD) для Items у server.js:

// ... (Налаштування express та sequelize)

// GET: Отримати всі речі разом з даними власника
app.get('/items', async (req, res) => {
    try {
        const items = await Item.findAll({ include: User });
        res.json(items);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// POST: Додати нову річ
app.post('/items', async (req, res) => {
    try {
        const { title, description, userId } = req.body;
        const newItem = await Item.create({ title, description, userId });
        res.status(201).json(newItem);
    } catch (error) {
        res.status(400).json({ error: error.message });
    }
});

// ... (PUT та DELETE реалізовані аналогічно за допомогою Item.update() та Item.destroy())

Для демонстрації роботи створимо нового користувача під іменем Томенко Ярослава та додамо їй бігову доріжку як її річ:

Скрін 3

4 ВІДПОВІДІ НА КОНТРОЛЬНІ ПИТАННЯ

    1. Що таке реляційна база даних?

      Реляційна база даних — це тип бази даних, яка зберігає та надає доступ до точок даних, пов’язаних між собою. Дані організовані у вигляді таблиць (рядків та стовпців), а зв’язки між таблицями встановлюються за допомогою первинних (Primary Key) та зовнішніх (Foreign Key) ключів.

    1. Для чого використовується MySQL?

      MySQL — це одна з найпопулярніших систем керування реляційними базами даних (RDBMS). Вона використовується для безпечного зберігання, організації, пошуку та модифікації великих обсягів структурованих даних у веб-застосунках.

    1. Що таке ORM?

      ORM (Object-Relational Mapping) — це технологія програмування, яка зв’язує бази даних з концепціями об’єктно-орієнтованих мов програмування. Вона створює “віртуальну об’єктну базу даних”, дозволяючи розробнику працювати з таблицями бази даних як з класами, а з рядками таблиць — як з об’єктами, не пишучи чисті SQL-запити.

    1. Для чого використовується Sequelize?

      Sequelize — це сучасна ORM-бібліотека для Node.js, що підтримує роботу на основі промісів (Promise). Вона використовується для роботи з реляційними базами (MySQL, PostgreSQL, SQLite) напряму через JavaScript, автоматично генеруючи SQL-запити, керуючи міграціями, транзакціями та зв’язками між таблицями.

    1. Яка різниця між hasMany та belongsTo?

      Це методи Sequelize для створення зв’язків.

      • hasMany застосовується до “батьківської” моделі (наприклад, User.hasMany(Item) — один користувач має багато речей).
      • belongsTo застосовується до “дочірньої” моделі (наприклад, Item.belongsTo(User) — конкретна річ належить одному користувачу). belongsTo автоматично додає зовнішній ключ (Foreign Key) до дочірньої таблиці.
    1. Що таке зв’язок One-to-Many?

      One-to-Many (Один-до-багатьох) — це тип відношення у реляційній базі даних, коли один запис у першій таблиці може бути пов’язаний з кількома записами у другій таблиці, але запис із другої таблиці пов’язаний лише з одним записом першої. (Наприклад: один Користувач -> багато Речей на платформі).

    1. Як виконати SQL-запит з Node.js?

      Виконати SQL-запит можна декількома способами:

      1. Використовуючи “сирі” (raw) драйвери, такі як пакет mysql2 (connection.query(“SELECT * FROM users”)).
      2. За допомогою ORM (як Sequelize) використовуючи вбудовані методи (User.findAll()).
      3. За допомогою ORM, але виконуючи сирий запит: sequelize.query(“SELECT * FROM users”).

ВИСНОВКИ

Під час виконання лабораторної роботи №2 я здобув практичні навички роботи з реляційними базами даних у середовищі Node.js.

Було успішно спроєктовано та створено базу даних MySQL для веб-застосунку “Library of Things” із таблицями users та items. Спочатку я ознайомився з прямим підключенням до СУБД за допомогою драйвера mysql2, що дозволило зрозуміти низькорівневий принцип взаємодії з базою даних через підготовлені SQL-запити.

Головним етапом роботи стало впровадження ORM-бібліотеки Sequelize. Це дозволило абстрагуватися від написання SQL-коду, описати структуру таблиць за допомогою JavaScript-моделей та налаштувати зв’язок “One-to-Many” (hasMany та belongsTo). REST API, розроблене у попередній лабораторній роботі (яке зберігало дані в тимчасовому масиві), було повністю рефакторене: тепер усі CRUD-операції виконуються асинхронно і зберігаються у персистентній базі даних MySQL. Використання Sequelize значно зменшило кількість шаблонного коду, підвищило читабельність та масштабованість бекенду.