bluegram - sequelize

박상은·2021년 12월 16일
0

🍃 blegram

목록 보기
9/20

1. DB와 연동

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

useruser가 N : M 관계로 인해 follows 테이블 생성
userpost가 N : M 관계로 인해 likes 테이블 생성
posthashtag가 N : M 관계로 인해 postHashtags 테이블 생성

2. 유저 및 DB 생성 및 권한 부여

# 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에 정의한대로 알아서 만들어줌

3. 테이블 정의 및 관계 설정

양이 많아서 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;

마무리

1. 어렵거나 힘들었던 점

기존에 몇 번 sequelize를 사용한 적이 있어서 그 세팅을 그대로 가져와서 사용해서 기본 세팅을 적용하는 데는 크게 어려움이 없었지만 관계 설정 부분에서 onDeletethrough같은 속성값에 대해 찾고 이해하는데 어려움이 있었습니다.
( 구글링과 sequelize v6 공식문서를 보고 해결했습니다. )

그리고 추가적으로 여기에 한 세팅이 계속 유지될 거라는 생각은 하지 않기 때문에 추후에 작업을 통해서 테이블이 추가되거나 컬럼이 변경될 수 있다고 생각합니다.

0개의 댓글