헬창 개발자
Node.js와 데이터베이스 본문
데이터 유형에 따른 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 |