MySQL_시퀼라이즈 사용하기(1)

이애옹·2023년 1월 3일
0

Node.js

목록 보기
26/32

📝 시퀼라이즈 사용하기

이제 노드에서 MySQL 데이터베이스에 접속 해 볼것이다! 이때 Sequelize 라이브러리를 사용하면, MySQL 작업을 쉽게 진행 할 수 있다.

시퀼라이즈ORM으로 분류된다. 여기서 ORM이란, 자바스크립트 객체와 데이터베이스의 릴레이션을 매핑 해 주는 도구를 말한다.

시퀼라이즈는 MySQL 외에 다른 데이터베이스와도 함께 사용할 수 있다. 여기서 시퀼라이즈를 쓰는 이유는, 자바스크립트 구문을 알아서 SQL로 바꿔준다는 장점 때문이다.

이러한 장점 덕분에, SQL 언어를 직접 사용하지 않아도 자바스크립트 만으로 MySQL을 조작 할 수 있다.

✔️ 시퀼라이즈 설치하기

일단 시퀼라이즈를 설치하기 전 새로운 프로젝트를 생성해준다.

express learn-sequelize --view=pug

learn-sequelize 라는 새로운 폴더가 생성되었다.

다음으로, cd learn-sequelize 명령어를 이용 해 해당 폴더로 이동한 뒤, npm 패키지들을 설치해줬다.

npm i

그 다음, 시퀼라이즈에 필요한 sequelizemysql2 패키지를 설치 해 준다. 그 다음, sequelize 커맨드를 사용하기 위해 sequelize-cli를 전역 설치 해 준다. 마지막으로 sequelize init 명령어를 호출 해 주면 된다.

npm i sequelize mysql2
npm i -g sequelize-cli
sequelize init

이것까지 완료하면,

이런 폴더가 완성된다.

이제 models 폴더 안의 index.js를 확인 해 준다.

'use strict';

const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const process = require('process');
const basename = path.basename(__filename);
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);
}

fs
  .readdirSync(__dirname)
  .filter(file => {
    return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
  })
  .forEach(file => {
    const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
    db[model.name] = model;
  });

Object.keys(db).forEach(modelName => {
  if (db[modelName].associate) {
    db[modelName].associate(db);
  }
});

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

module.exports = db;

해당 파일을 그대로 사용 할 경우, 에러가 발생하기도 하고 필요 없는 부분도 포함되어 있다고 하니 파일을 수정해주자.

const path = require('path');
const Sequelize = require('sequelize');

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

const sequelize = new Sequelize(config.database, config.username, config.password, config);

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

module.exports = db;

이렇게 수정해 주면 된다 ㅎ.ㅎ


✔️ MySQl 연결하기

시퀼라이즈 을 통해 익스프레스 앱과 MySQL을 연결해야 한다.

app.js에서 다음과 같이 구문을 추가해준다.


var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var sequelize = require('./models').sequelize; //추가

var app = express();
sequelize.sync(); //추가

require('./models')require('./routes/index')와 같다. 폴더 내의 index.js 파일은 require시 생략 가능하다.

sync 메서드를 사용하면 서버 실행 시 알아서 MySQL과 연동된다.


✔️ 모델 정의하기

이제 MySQL에서 정의한 테이블을 시퀼라이즈에서도 정의 해 줘야 한다. MySQL의 테이블은 시퀼라이즈의 모델과 대응된다. 여기서 시퀼라이즈는 MySQL의 테이블과 모델을 연결해주는 역할을 한다.

User과 Comment 모델을 만들어 users 테이블과 comments 테이블을 연결 해 보자!! 시퀼라이즈는 기본적으로 모델 이름은 단수, 테이블 이름은 복수로 지정한다.

먼저, models 폴더 안에 user.js 파일을 생성해줬다.

module.exports = (sequelize, DataTypes) => {
  return sequelize.define('user', {
    name: {
      type: DataTypes.STRING(20),
      allowNull: false,
      unique: true,
    },
    age: {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull: false,
    },
    married: {
      type: DataTypes.BOOLEAN,
      allowNull: false,
    },
    comment: {
      type: DataTypes.TEXT,
      allowNull: true,
    },
    created_at: {
      type: DataTypes.DATE,
      allowNull: false,
      defaultValue: sequelize.literal('now()'),
    },
  }, {
    timestamps: false,
  });
};

시퀼라이즈는 알아서 id를 기본 키로 연결하므로 id 컬럼은 입력할 필요가 없다. sequelize, define 메서드로 테이블명과 각 컬럼의 스펙을 입력 해 준다.
(MySQL 테이블과 컬럼 내용이 일치해야 한다.)

MySQL과 시퀼라이즈의 자료형은 다음과 같다.

MySQL시퀼라이즈
VARCHARSTRING
INTINTGER
TINYINTBOOLEAN
DATETIMEDATE

그 외에 추가적으로 알아야 하는 부분은 다음과 같다~!

  • allowNull = NOT NULL 옵션과 동일
  • unique = UNIQUE 옵션과 동일
  • defaultValue = 기본값
  • now()를 사용해야 하므로 sequelize.literal 메서드 안에 넣어서 입력(인자로 넣은 문자를 그대로 사용)
  • timestamps 속성이 ture면 생성 시간과 수정 시간 자동으로 입력

그 다음, models 폴더 내에 comment.js 파일도 생성했다.

module.exports = (sequelize, DataTypes) => {
  return sequelize.define('comment', {
    comment: {
      type: DataTypes.STRING(100),
      allowNull: false,
    },
    created_at: {
      type: DataTypes.DATE,
      allowNull: true,
      defaultValue: sequelize.literal('now()'),
    },
  }, {
    timestamps: false,
  });
};

해당 구문을 보면, users 테이블과 관계를 정의 한 부분이 없는것을 확인 할 수 있는데, 따로 추가가 가능하다! 그건 좀 뒷부분에~

이제 모델을 다 생성했으니, index.js와 연결 해 줘야 한다.


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

db.User = require('./user')(sequelize, Sequelize); //추가
db.Comment = require('./comment')(sequelize, Sequelize); //추가

module.exports = db;

db라는 객체에 User와 Comment 모델을 담아두었다. 앞으로 db 객체를 require 하여 User와 Comment 모델에 접근 할 수 있다.

마지막으로, config 폴더 안에 있는 config.json 파일을 수정 해 준다.

  "development": {
    "username": "root",
    "password": "[root 비밀번호]",
    "database": "nodejs",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "operatorsAliases" : false
  },

비밀번호는 본인이 지정한 비밀번호를 입력 해 주면 된다.

test 환경 일 경우에는 test 부분을, 배포 환경 일 때는 production 부분을 수정 해 주면 된다.


✔️ 관계 정의하기

사용자 한 명은 댓글을 여러 개 작성할 수 있지만, 하나의 댓글에 사용자(작성자)가 여러명일수는 없다.

이러한 관계를 일대다 관계 라고 한다! 일대일관계는 사용자와 사용자의 정보 테이블을 예를 들 수 있다. 사용자 한 명은 자신의 정보를 담고 있는 테이블과 관계가 있고, 정보 테이블도 한 사람만을 가리킨다.

다대다 관계로는 게시글 테이블과 해시태그 테이블을 예로 들 수 있는데, 한 게시글에는 해시태그가 여러 개 달릴 수 있고, 한 해시태그에도 여러 게시글이 달릴 수 있다.

MySQL 에서는 JOIN이라는 기능으로 테이블 간의 관계를 파악해 결과를 도출한다. 시퀼라이즈는 JOIN 기능도 알아서 구현 해 준다. 하지만, 시퀼라이즈에게 테이블 간에 어떤 관계가 있는지 알려줘야한다.

1) 1:N

시퀼라이즈에서는 1:N 관계hashMany라는 메서드로 표현한다. users 테이블의 로우 하나를 불러 올 때 연결된 comments 테이블의 로우들도 같이 불러 올 수 있다.

반대로, belongsTo 메서드도 있다. comments 테이블의 로우를 불러올 때 연결된 users 테이블의 로우를 가져온다.

models/index.js에 추가로 코드를 넣어준다.

db.User = require('./user')(sequelize, Sequelize); //추가
db.Comment = require('./comment')(sequelize, Sequelize); //추가

db.User.hasMany(db.Comment, { foreignKey: 'commenter', sourceKey: 'id' });
db.Comment.belongsTo(db.User, { foreignKey: 'commenter', targetKey: 'id' });

module.exports = db;

시퀼라이즈는 방금 정의한 대로 테이블 간 관계를 파악해서 commenter 컬럼을 추가하고, 외래키도 추가한다.

외래키 컬럼은 commenter고, usersid 컬럼을 가리키고 있다.

foreignKey 속성commenter를 넣어준다. hashMany 메서드에서는 sourceKey 속성id를 넣어주고, belongsTo 메서드에서는 targetKey 속성id를 넣어준다. User 모델idComment 모델commenter 컬럼에 들어가는 것 이다.

이 상태에서 npm start를 콘솔 창에 입력 해 주면,

Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'users' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `users` FROM `nodejs`
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'comments' AND TABLE_SCHEMA = 'nodejs'
Executing (default): SHOW INDEX FROM `comments` FROM `nodejs`

다음과 같은 코드가 나온다! 시퀼라이즈가 스스로 실행 해 주는 SQL문이라고 한다.

2) 1:1

1:1 관계에서는 hasOne 메서드를 사용한다. 사용자 정보를 담고 있는 가상의 info 모델이 있다고 하면 다음과 같이 작성하면 된다.

db.User.hasOne(db.Info, { foreignKey: 'user_id', sourceKey: 'id' });
db.Info.belongsTo(db.User, { foreignKey: 'user_id', targetKey: 'id' });

belingsTohashOne이 반대여도 상관없다. (일대일이니까)

3) N:M

시퀼라이즈에서는 다대다 관계를 표현하기 위해 belongsToMany 메서드를 사용한다. 게시글 정보를 담고 있는 가상의 Post 모델과 해시태그 정보를 담고 있는 가상의 Hashtag 모델이 있다고 하면 다음과 같이 표현할 수 있다.

db.Post.belongsToMany(db.Hashtag, { through : 'PostHashtag' });
db.Hashtag.belongsToMany(db.Post, { through : 'PostHashtag' });

다대다 관계 특성상 새로운 모델이 생성된다. through 속성에 그 이름을 적어주면 된다. 새로 생성된 PostHashtag 모델에는 게시글과 해시태그 아이디가 저장된다.

다대다 관계에서는 데이터를 조회할 때 여러 단계를 거쳐야 한다. 먼저, 노드 해시태그를 Hashtag 모델에서 조회하고, 가져온 태그의 아이디(1)를 ㅏ탕으로 PostHashtag 모델에서 hashtagId가 1인 postId들을 찾아 Post 모델에서 정보를 가져온다.

시퀼라이즈는 이 과정을 편하게 하는 몇 가지 메서드를 제공한다.

async(req, res, next) => {
  const tag = await Hashtag.find({where : {title : '노드'}});
  const posts = await tag.getPosts();
}

먼저 해시태그를 찾으면 그 해시태그에서 바로 getPost 메서드를 사용할 수 있다. get+모델 이름의 복수형이다.

async/await 형식이 익숙하지 않다면 프로미스 형식으로도 작성 가능하다.

HashTag.find({where : {title : '노드'}})
  .then(tag => tag.getPosts())
  .then(posts => console.log(posts));
 

비슷한 것으로 add+모델 이름의 복수형 메서드도 있다. 두 테이블과 다대다관계를 추가 해 준다.

다음 코드는 title이 노드인 해시태그와 게시글 아이디가 3인 게시글을 연결하는 코드이다.

 async(req, res, next) => {
    const tag = await Hashtag.find({where : {title : '노드'}});
    await tag.setPosts(3);
  }

이렇게 작성하면 PostHashtag 모델에 PostId가 3이고 hashtagId가 1인 로우가 생성된다.

profile
안녕하세요

0개의 댓글