sequelize(작성 중)

3 분 소요

시퀄라이즈

ORM(object-relational Mapping)인 시퀄라이즈를 사용해보자. ORM의 편한 부분은 자바스크립트 구문을 SQL 쿼리문으로 바꿔주기 때문이다.

설치

express 프로젝트를 생성 후 sequelize를 설치한다.

시퀄라이즈 커맨드 사용을 위한 sequelize-cli 도 설치해준다.

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

Sequelize CLI [Node: 12.18.2, CLI: 6.2.0, ORM: 6.3.5]

Created "config\config.json"
Successfully created models folder at "C:\Users\lkic1\NodejsProjects\learn-sequelize\models".
Successfully created migrations folder at "C:\Users\lkic1\NodejsProjects\learn-sequelize\migrations".
Successfully created seeders folder at "C:\Users\lkic1\NodejsProjects\learn-sequelize\seeders".

이때 기본 생성되는 models/index.js를 아래와 같이 수정해주고 사용하자.

const Sequelize = require('sequelize');
// const User = require('./user');
// const Comment = require('./comment');

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

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

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

// db.User = User;
// db.Comment = Comment;

User.init(sequelize);
Comment.init(sequelize);

User.associate(db);
Comment.associate(db);

module.exports = db;

mysql 연결

app.js

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

var app = express();
sequelize.sync();
...

sync()를 사용하면 서버 실행 시 MySQL과 연동된다.

모델 정의하기

SQL서 미리 정의된 테이블을 시퀄라이즈에도 정의해야 한다.

시퀄라이즈는 기본적으로 모델 이름을 단수형으로, 테이블 이름을 복수형으로 사용한다.

데이터 테이블은 아래 형식과 같다

users

+-----------+--------------+------+-----+-------------------+-------------------+
| Field     | Type         | Null | Key | Default           | Extra             |
+-----------+--------------+------+-----+-------------------+-------------------+
| id        | int          | NO   | PRI | NULL              | auto_increment    |
| name      | varchar(20)  | NO   | UNI | NULL              |                   |
| age       | int unsigned | NO   |     | NULL              |                   |
| married   | tinyint      | NO   |     | NULL              |                   |
| comment   | text         | YES  |     | NULL              |                   |
| create_at | datetime     | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+-----------+--------------+------+-----+-------------------+-------------------+

comments

+------------+--------------+------+-----+-------------------+-------------------+
| Field      | Type         | Null | Key | Default           | Extra             |
+------------+--------------+------+-----+-------------------+-------------------+
| id         | int          | NO   | PRI | NULL              | auto_increment    |
| commenter  | int          | NO   | MUL | NULL              |                   |
| comment    | varchar(100) | NO   |     | NULL              |                   |
| created_at | datetime     | NO   |     | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
+------------+--------------+------+-----+-------------------+-------------------+

models/users.js

const { sequelize } = require(".");
const { DataTypes } = require("sequelize/types");

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,
    },
    create_at: {
        type: DataTypes.DATE,
        allowNull: false,
        defaultValue: DataTypes.NOW,
    },
  },{
    timestamps: false,
  }
  );
};

models/comment.js

const { sequelize } = require(".");
const { DataTypes } = require("sequelize/types");

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

config/config.json을 커넥션과 일치하게 수정하면 된다.

관계 정의하기

유저 테이블과 코멘트 테이블의 관계를 정의해보자. 사용자는 한명이지만, 사용할 수 있는 댓글의 개수 제한은 없기 떄문에 일대다 관계이다.

다른 관계로는 일대일 다대다 관계가 있다. 다대다는 해시태그(#)가 될 수 있다. 게시글은 해시태그를 여러개 포함할 수 있으며 해시태그가 포함된 게시글 또한 여러개이다.

1:N

hasMany메서드를 통해 유저 테이블의 로우 하나를 불러올 때 연결된 코멘트 테이블의 로우들도 같이 불러올 수 있다.

belongsTo메서드를 통해 코멘트 테이블의 로우를 불러올 때 연결된 유저 테이블의 로우도 같이 불러올 수 있다.

models/index.js

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

db.User = User(sequelize, Sequelize);
db.Comment = Comment(sequelize, Sequelize);

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

1:1

hasOne메서드를 통해 직접 연결된 테이블을 불러올 수 있다.

belongsTo hasOne과 순서가 반대가 되어도 상관없다 일대일 대응이기 때문이다.

N:M

belongsToMany메서드를 통해 코멘트 테이블의 로우를 불러올 때 연결된 유저 테이블의 로우도 같이 불러올 수 있다. 둘 다 위 메서드를 사용하여 불러온다.

자세한 사용법은 이후 9장에서 포스팅 하겠다.

쿼리 사용법.

INSERT INTO users (name, age, married, comment) VALUES ('zero', 24, 0, '자기소개')

User.create({
  name: 'zero',
  age: 24,
  married: false,
  comment: '자기소개',
});

여기서 주의할 점은 married 콜럼값이 시퀄라이즈에서 정의된 자료형으로 넣는다는 것이다 false가 아닌 0을 넣는다면 오류를 발생시키며, 시퀄라이즈는 알아서 MySQL 자료형으로 바꿔주기 때문에 옵션에 부합하는 자료형을 넣는 것이 중요하다.

SELECT * FROM users

User.findAll({});

SELECT * FROM users LIMIT 1

User.find({});

SELECT name, age FROM users

User.findAll({
  attributes: ['name', 'married'],
});
Refernce
  • 조헌영, Node.js 교과서, 길벗, 7장 MySQL