sequelize
는 ORM (Object Relational Mapping)이기 때문에 JS 문법을 통해서 데이터베이스를 관리할 수 있습니다.
sequelize
를 사용한 이유는 mysql2
같은 드라이버만 바꿔주면 해당 데이터베이스에 맞게 자동적으로 SQL을 변경시켜서 적용하기 때문에 관리하기 더 편기도 하고, 테이블이 변경될 경우 force: true
로 간단하게 리셋 시킬 수 있기 때문에 선택했습니다.
설치 및 실행
1. npm i sequelize sequelize-cli mysql2
2. npx sequelize init
테이블 설계
1. 기본 테이블: users
, posts
, comments
, hashtags
, images
2. 중간 테이블: postHashtags
, likes
, follows
user
와 user
가 N : M 관계로 인해 follows
테이블 생성
user
와 post
가 N : M 관계로 인해 likes
테이블 생성
post
와 hashtag
가 N : M 관계로 인해 postHashtags
테이블 생성
# DB 생성
CREATE DATABASE bluegramDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
# 유저 생성 및 패스워드 지정 ( 패스워드는 혹시 모르니 명시안함 )
CREATE user bluegramUser@'%' IDENTIFIED BY '비밀번호알아서작성';
# 유저 권한 부여
GRANT ALL PRIVILEGES ON bluegramDB.* TO 'bluegramUser'@'%';
# 유저 권한 부여한거 적용
flush privileges;
# 유저 삭제
drop user bluegramUser@'%';
# DB 삭제
drop database bluegram;
# 나머지 테이블 생성부분은 sequelize에 정의한대로 알아서 만들어줌
양이 많아서 sequelize
등록, user
테이블 정의, user
관계 설정 관련 코드만 첨부하고 나머지는 GitHub링크로 대체하겠습니다.
// 아래 코드들 app.js의 각 부분에 추가
import db from "./models/index.js"
db.sequelize
.sync({ force: false, alter: false })
.then(() => console.log("DB 연결 성공!"))
.catch(error => console.error("DB 연결 실패 >> ", error));
import dotenv from "dotenv";
dotenv.config();
const configDB = {
development: {
database: process.env.DATABASE_NAME,
username: process.env.DATABASE_USER_NAME,
password: process.env.DATABASE_PASSWORD,
host: process.env.DATABASE_HOST,
dialect: "mysql",
logging: false,
freezeTableName: true
},
test: {
database: process.env.DATABASE_NAME,
username: process.env.DATABASE_USER_NAME,
password: process.env.DATABASE_PASSWORD,
host: process.env.DATABASE_HOST,
dialect: "mysql",
logging: false,
freezeTableName: true
},
production: {
database: process.env.DATABASE_NAME,
username: process.env.DATABASE_USER_NAME,
password: process.env.DATABASE_PASSWORD,
host: process.env.DATABASE_HOST,
dialect: "mysql",
logging: false,
freezeTableName: true
}
}
export default configDB;
import dotenv from "dotenv";
dotenv.config();
import Sequelize from "sequelize";
import configDB from "../config/config.js";
const db = {};
const env = process.env.NODE_ENV || "development";
const config = configDB[env];
const sequelize = new Sequelize(config.database, config.username, config.password, config);
// 테이블 불러오기
import User from "./user.js";
import Post from "./post.js";
import Comment from "./comment.js";
import Hashtag from "./hashtag.js";
import Image from "./image.js";
// db에 테이블 등록
db.User = User(sequelize, Sequelize);
db.Post = Post(sequelize, Sequelize);
db.Comment = Comment(sequelize, Sequelize);
db.Hashtag = Hashtag(sequelize, Sequelize);
db.Image = Image(sequelize, Sequelize);
// associate
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
export default db;
const User = (sequelize, DataTypes) => {
const User = sequelize.define(
"User",
{
_id: {
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
autoIncrement: true,
primaryKey: true,
comment: "유저의 아이디 ( 유저를 식별할 값 )",
},
id: {
type: DataTypes.STRING(20),
allowNull: false,
unique: true,
comment: "유저가 로그인할 때 사용할 아이디"
},
password: {
type: DataTypes.STRING(100),
allowNull: false,
comment: "유저가 로그인할 때 사용할 비밀번호 ( bcrypt 적용 )"
},
name: {
type: DataTypes.STRING(20),
allowNull: false,
comment: "유저 성명"
},
phone: {
type: DataTypes.STRING(11),
allowNull: false,
comment: "유저 전화번호"
},
birthday: {
type: DataTypes.STRING(8),
allowNull: false,
comment: "유저 생년월일"
}
},
{
sequelize,
timestamps: true,
paranoid: false,
underscored: false,
modelName: "User",
tableName: "users",
charset: "utf8",
collate: "utf8_general_ci",
},
);
User.associate = db => {
// 팔로우 ( N : M )
db.User.belongsToMany(db.User, { through: "follows", as: "Followings", foreignKey: "FollowerId", onDelete: "cascade" });
db.User.belongsToMany(db.User, { through: "follows", as: "Followers", foreignKey: "FollowingId", onDelete: "cascade" });
// 유저와 게시글 ( 1 : N )
db.User.hasMany(db.Post, { onDelete: "cascade" });
// 유저와 댓글 ( 1 : N )
db.User.hasMany(db.Comment, { onDelete: "cascade" });
// 좋아요 ( N : M ) ( 유저와 게시글 )
db.User.belongsToMany(db.Post, { through: "likes", as: "Liker", foreignKey: "PostId", onDelete: "cascade" });
// 유저와 이미지 ( 1 : N )
db.User.hasMany(db.Image, { onDelete: "cascade" });
};
return User;
};
export default User;
기존에 몇 번 sequelize
를 사용한 적이 있어서 그 세팅을 그대로 가져와서 사용해서 기본 세팅을 적용하는 데는 크게 어려움이 없었지만 관계 설정 부분에서 onDelete
나 through
같은 속성값에 대해 찾고 이해하는데 어려움이 있었습니다.
( 구글링과 sequelize v6 공식문서를 보고 해결했습니다. )
그리고 추가적으로 여기에 한 세팅이 계속 유지될 거라는 생각은 하지 않기 때문에 추후에 작업을 통해서 테이블이 추가되거나 컬럼이 변경될 수 있다고 생각합니다.