헬창 개발자

Node.js와 데이터베이스 본문

공부방

Node.js와 데이터베이스

찬배 2022. 9. 4. 23:05

데이터 유형에 따른 SQL 종류

  • SQL
    • 서로 관계가 있는 데이터 구조를 만들고 싶을 경우에 사용한다.
    • 각 관계에 대한 데이터가 자주 수정되는 경우에 사용한다.
    • 서비스에 명확한 스키마가 중요할 경우에 사용한다.
  • NoSQL
    • 데이터의 형태를 정확히 규명할 수 없는 경우에 사용한다.
    • 읽기(Read)가 변경(Update)보다 많은 데이터일 경우 사용한다.
    • 데이터의 양이 많아 수평으로 확장해야 하는 경우 사용한다.

개발 환경 설정

MySQL 설치 생략

MySQL Workbench를 이용하여 roadbook 스키마에 customers, purchase 테이블을 만들어주자

ORM : Sequelize

  • ORM(Object Relational Mapping)이란? 객체와 관계를 맵핑해주는 역할 ORM을 사용하면 SQL이 아닌 클래스나 메서드를 통해 테이터베이스 CRUD 작업을 할 수 있다.
  • Sequelize ORM 중 Node.js 에서 가장 인기각 있고 mysql 뿐만 아니라 mariaDB, SQLite, MSSQL에서도 지원한다. 데이터를 객체 형태로 변환하는 것뿐만 아니라 promise패턴을 사용할 수 있도록 해주어 비동기 처리도 then이나 async/await로 할 수 있게 해준다.
npm install sequelize sequelize-cli mysql2

sequelize와 sequelize 명렁어를 사용할 수 있게 해주는 sequelize-cli와 MySQL 드라이버 역할을 하는 MySQL2 모듈을 작업 풀더 최상위에 설치한다.

cd chapter05/sequelize // 자신의 프로젝트 폴더
npx sequelize init

sequelize 명령어를 통해 sequelize를 초기화 시켜줍니다.

초기화를 진행하면 해당경로에 다음 폴더가 생성이된다.

  • config/ : DB root password, database, host 등의 데이터베이스 연동정보를 저장하는 폴더
  • migrations/ : 데이터베이스를 옮기거거나 합치는 마이그레이션에 필요한 데이터가 저장되는 폴더
  • models/ : 데이터베이스 모델을 저장하는 폴더
  • seeders/ : 테스트에 필요한 데이터를 저장하는 폴더

먼저 config 파일을 자신의 데이터베이스 정보에 맞게 수정을 해주자

  • 데이터베이스 정보 저장 (squelize/config/config.json)
module.exports = (sequelize, DataTypes) => {
    const newCustomer = sequelize.define("new_customer", { // 테이블 이름
        name: { // 컬럼 생성
            type: DataTypes.STRING(20), // 데이터 타입 정의
            allowNull: false // Null 허용 여부 정의
        },
        age: {
            type: DataTypes.INTEGER,
            allowNull: false
        },
        sex: {
            type: DataTypes.STRING(10),
            allowNull: false
        },
        joined_date: {
            type: 'TIMESTAMP',
            defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
            allowNull: false
        },
    }, {
        timestamps: false
    });
    return newCustomer;
};
  • 열에 대한 옵션
    • type : 데이터 타입을 정의합니다.
    • allowNull : Null 허용 여부를 정의합니다.
    • autoincrement : 자동으로 숫자가 증가하는 여로 지정할지에 대한 여부를 정의 합니다.
    • defaultValue : 기본 값을 지정합니다.
    • comment : 열에 대한 설명을 지정합니다.
    • freezeTableName : true로 설정하면 이름을 복수로 설정하지 않는다.
    • timestamps : createdAt, updatedAt 열을 추가할지의 여부를 지정합니다.
  • purchase객체를 ORM로 작성하기 (squelize/models/purchase.js)
module.exports = (sequelize, DataTypes) => {
    const newPurchase = sequelize.define("new_purchase", {
        customer_id: {
            type: DataTypes.INTEGER,
            allowNull: false,
        },
        book_name: {
            type: DataTypes.STRING(20),
            allowNull: false
        },
        purchase_date: {
            type: 'TIMESTAMP',
            defaultValue: sequelize.literal('CURRENT_TIMESTAMP'),
            allowNull: false
        },
    }, {
        freezeTableName: true,
        timestamps: false
    });
    return newPurchase;
};
  • index.js 수정 (squelize/models/index.js)

const Sequelize = require('sequelize');

const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};

let sequelize;
if (config.use_env_variable) {
  sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
  sequelize = new Sequelize(config.database, config.username, config.password, config);
}

db.sequelize = sequelize;
db.Sequelize = Sequelize;

db.newCustomer = require('./customer')(sequelize, Sequelize);
db.newPurchase = require('./purchase')(sequelize, Sequelize);

db.newCustomer.hasMany(db.newPurchase, { foreignKey: 'customer_id', sourceKey: 'id' });
db.newPurchase.belongsTo(db.newCustomer, { foreignKey: 'customer_id', sourceKey: 'id' });

module.exports = db;

자동으로 생성된 models/index.js 파일 안에는 sequelize를 초기화하기 위한 내용이 담겨져 있다.

필요한 부분만 남기고 지우고 변수를 정리하자면

env : 개발모드, 테스트모드를 정하는 변수

config : 연결할 데이터베이스 정보가 담긴 config.json을 불러오는 config 변수

db : 연결된 데이터베이스로부터 객체를 받는 변수

테이블간의 관계를 설정해줘야하는데 customers와 purchase 테이블의 경우는 하나의 고객이 여러 번의 구매 기록이 있는 것이 가능하므로 1:N 관계를 설정해야하며 hasMany를 통해 관계를 맺어주면 된다. 1:1은 belongsTo, N:M은 belongsToMany을 사용하면 된다.

 

테이블 관계 생성 (squelize/app.js)

const { sequelize } = require('./models/index.js');

const driver = () => {
    sequelize.sync().then(() => {
        console.log('초기화 완료');
    }).catch((err) => {
        console.error('초기화 실패');
        console.error(err);
    });
};
driver();

app.js와 models/ 폴더가 있는 위치에서 (node 경로/app.js) 명령어를 통해 데이터베이스에 테이블을 생성해보자

이제 터미널을 켜서 Mysql에 진짜로 테이블이 생성되었는지 확인해봅시다.

mysql -u -p명령어을 실행하고 use db명령어로 config.json 파일에서 지정해준 데이터베이스에 접속합니다.

 

sequelize CRUD

sequelize를 이용해서 데이터베이스를 직접 조작하지 않고 노드 안에서 어떻게 CRUD 작업을 할 수 있는지 살펴보자

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>회원가입</title>
  </head>
  <body>
    <h1>정보를 입력하세요.</h1>
    <form action="/customer" method="POST">
      <table>
        <tr>
          <td><input type="text" name="name" placeholder="이름 : " /></td>
        </tr>
        <tr>
          <td><input type="text" name="age" placeholder="나이 :" /></td>
        </tr>
        <tr>
          <td><input type="text" name="sex" placeholder="성별 :" /></td>
        </tr>
      </table>
      <input type="submit" value="전송하기" />
    </form>
  </body>
</html>

<form>을 통해 얻어오는 클라이언트 화면을 생성해주자

 

const morgan = require('morgan');
const models = require('./models');

const express = require('express');
const app = express();

/* 포트 설정 */
app.set('port', process.env.PORT || 8080);

/* 공통 미들웨어 */
app.use(morgan('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get('/', (req, res, next) => { // READ
    models.newCustomer.findAll()
        .then((customers) => {
            res.send(customers);
        })
        .catch((err) => {
            console.error(err);
            next(err);
        });
});

app.get('/customer', (req, res) => {
    res.sendFile(__dirname + '/customer.html');
});

app.post('/customer', (req, res) => { // CREATE
    let body = req.body;

    models.newCustomer.create({
        name: body.name,
        age: body.age,
        sex: body.sex,
    }).then(result => {
        console.log('customer created..!');
        res.redirect('/customer');
    }).catch(err => {
        console.log(err);
    })
});

/* 서버와 포트 연결.. */
app.listen(app.get('port'), () => {
    console.log(app.get('port'), '번 포트에서 서버 실행 중 ..')
});

‘/’ 라우터에서는 new_customers 테이블에 있는 정보를 불러오는데 이때 findAll()이라는 함수를 사용해서 모델안의 모든 정보를 SELECT하는 함수이다. 이 외도 findOne(), find() 함수를 통해 한 개의 원하는 데이터만 읽어올 수 있다. count()함수, findAndCount()함수도 READ 작업에 속한다.

‘/customer’ 라우터에서 customer.html 파일을 불러오고 해당 form에 데이터를 아래처럼 입력하면 new_customers 테이블의 해당하는 컬럼에 데이터를 저장한다.

 

결과를 확인해보면 테이블에 알맞게 저장된것을 확인할 수 있다.

'공부방' 카테고리의 다른 글

실시간 소켓 통신 구현을 해보자  (2) 2022.10.05
Node.js 환경에서 NoSQL : MongoDB 사용하기  (0) 2022.09.22
Node.js를 이용한 웹파싱  (0) 2022.09.01
API????????  (3) 2022.08.21
express 미들웨어  (0) 2022.08.19
Comments