본문 바로가기

백엔드/DB

데이터 모델링 (with Sequelize)

 

 

개요

 

최근 개인 프로젝트를 시작했다  참고로  프론트 뿐만 아니라  백엔드 서버 까지 내가 직접 구축해서  개발을 하기로 했다  본격적인  서버 구축에  이어   api 개발에 있어서 선행되어야 할것이  바로 데이터 모델링이다  필자는  MySQL을 데이터베이스로 사용하게 되었는데   sql까지는 아직 지식이 없어서   Sequelize를 사용하게 되었다

 

시퀄라이즈는 Node.js에서 MySQL을 쉽게 다룰 수 있도록 도와주는 라이브러리로 ORM으로 분류된다  SQL을 모르더라도 데이터베이스 관리가 가능하기에  필자는  시퀄라이즈를 사용하게 되었다.

 

 

 

테이블  세팅

 

모델링을 하기전  필자의  프로젝트에서  어떤 테이블이 필요한지 살펴보겠다   

 

필자가 만들고자 하는 프로젝트는  트위터, 페이스북과  같은  커뮤니티형 SNS이다  게시판이 아마도  메인 기능이 될것이다  

 

이렇게 설명하니 굉장히 간단해보이지만  그렇지 않다  게시판도 뜯어보면 정말 다양한 데이터가 있다  

 

게시글이 있을 것이고  그 게시글을 작성한 유저 그리고 게시글에 들어가는 이미지 , 댓글, 대댓글, 댓글을 작성한 유저 등이 있을 것이다 또한  필자는 해쉬태그 기능도  구현할 예정이기에  해쉬태그도 들어갈 것이다.

 

따라서 필자는  테이블을  크게   다음과 같이  분류하고  세팅했다.

1. 게시글  2. 유저  3. 이미지  4. 댓글   5. 해쉬태그

시퀄라이즈를 통해 MySQL과 연결하기 위해서는 MySQL에서 정의한 테이블을 시퀄라이즈에서도 정의해야 한다 (MySQL 테이블 = 시퀄라이즈의 모델)    다음은  테이블 별로 모델을 어떻게 정의 했는지에 대한 내용이다

 

 

 

1. 게시글

 

module.exports = (sequelize, DataTypes) => {
  const Post = sequelize.define(
    "Post",
    {
      content: {
        type: DataTypes.TEXT,
        allowNull: false,
      },
    },
    {
      charset: "utf8mb4",
      collate: "utf8mb4_general_ci", 
    }
   
  );
  Post.associate = (db) => {
    db.Post.belongsTo(db.User); //post.addUser post.getUser
    db.Post.belongsToMany(db.Hashtag, { through: "PostHashtag" });
    db.Post.belongsToMany(db.User, { through: "Like", as: "Likers" });
    db.Post.hasMany(db.Comment);
    db.Post.belongsTo(db.Post, { as: "Retweet" });
    db.Post.hasMany(db.Post, { as: "Retweets", foreignKey: "RetweetsId" });
    db.Post.hasMany(db.Image);
  };
  return Post;
};

 

2. 유저  

 

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define(
    "User",
    {
      email: {
        type: DataTypes.STRING(30), 
        allowNull: false, 
        unique: true, 
      },
      nickname: {
        type: DataTypes.STRING(30),
        allowNull: false,
      },
      password: {
        type: DataTypes.STRING(100),
        allowNull: false,
      },
      intro: {
        type: DataTypes.STRING(30),
        allowNull: true,
      },
    },
    {
      charset: "utf8",
      collate: "utf8_general_ci", //한글 저장
    }
  );
  User.associate = (db) => {
    db.User.hasMany(db.Post);
    db.User.hasMany(db.Comment);
    db.User.hasOne(db.Image, { as: "ProfileImage" });
    db.User.belongsToMany(db.Post, { through: "Like", as: "Liked" });
    db.User.belongsToMany(db.User, {
      through: "Follow",
      as: "Followers",
      foreignKey: "FollowingId",
    });
    db.User.belongsToMany(db.User, {
      through: "Follow",
      as: "Followings",
      foreignKey: "FollowerId",
    });
  }; 
  return User;
};

 

3. 이미지 

 

module.exports = (sequelize, DataTypes) => {
  const Image = sequelize.define(
    "Image",
    {
      src: {
        type: DataTypes.STRING(600),
        allowNull: true,
      },
    },
    {
      charset: "utf8",
      collate: "utf8_general_ci",
    }
  );
  Image.associate = (db) => {
    db.Image.belongsTo(db.Post);
    db.Image.belongsTo(db.User, { as: "ProfileImage" });
  };
  return Image;
};

 

  4. 댓글

 

module.exports = (sequelize, DataTypes) => {
  const Comment = sequelize.define(
    "Comment",
    {
      content: {
        type: DataTypes.TEXT,
        allowNull: false,
      },
      isReply: {
        type: DataTypes.BOOLEAN,
        allowNull: true,
      },
    },
    {
      charset: "utf8mb4",
      collate: "utf8mb4_general_ci", //이모티콘 저장
    }
  );
  Comment.associate = (db) => {
    db.Comment.belongsTo(db.User);
    db.Comment.belongsTo(db.Post);
    db.Comment.hasMany(db.Comment, { as: "Reply" });
  };
  return Comment;
};

 

 5. 해쉬태그

 

module.exports = (sequelize, DataTypes) => {
  const Hashtag = sequelize.define(
    "Hashtag",
    {
      name: {
        type: DataTypes.STRING(false),
        allowNull: false,
      },
    },
    {
      charset: "utf8mb4",
      collate: "utf8mb4_general_ci", //이모티콘 저장
    }
  );
  Hashtag.associate = (db) => {
    db.Hashtag.belongsToMany(db.Post, { through: "PostHashtag" });
  };
  return Hashtag;
};

 

시퀄라이즈의 자료형과 MySQL의 자료형은 다르다 어떻게 다른지는 다음 표를 참고하면 좋을 것 같다.

 

 

 

모델링

 

모델링을 하면서 엔티티, 관계 유형, 속성 등  처음 보았을 때는  사실  별로 와닿지 않았고  다소 이론적인 내용에 가깝게 보였다  

 

그러나 시퀄라이즈를 작성하면서  모델링에 대한 원론적인 내용이 그대로 활용된다는 것을 체감했다.

 

 

 

1. associate 

 

 두 모델이  서로 연관 관계가 있다면 associate이다 

 

프로젝트에 적용을 해보면  게시글 모델인  Post 와  유저 모델인 User는  각각  작성자와 작성자가 작성한 게시글이라는 

연관 관계를 가지고 있다. 이밖에도  게시글과  댓글,  게시글과  이미지 등이  연관 관계를 가지고 있다고 볼 수 있다

 

2. 참조의 개념

 

참조 대상 : 부모 테이블, 피참조(참조를 받는 대상) : 자식 테이블

 

부모 테이블의 해당 속성을 참조하게 된다면  해당 속성을 매개로 하여 부모 테이블의 column 들을 모두 불러올 수 있다 

 

참조한 속성은 foreign key 설정을 통해  다른 테이블이 참조할 수 있도록 설정한다.

 

2-1 hasOne / belongsTo

 

hasOne
1:1 관계의 두 모델이 있을때, 부모(1) 테이블이 자식(1) 테이블에게 참조할 수 있는 속성을 제공하고자 할 때

 

 

belongsTo
1:1 관계의 두 모델이 있을때, 자식(1) 테이블이 부모(1) 테이블의 한 속성을 참조하고자 할 때

 

 

 

   프로젝트에서 적용을 해보면 

 

  • 각 유저(User Model)는 한 개의 프로필 이미지(Image Model)를 가지고 있다 
  • 따라서 유저 모델과 이미지 모델의 관계는 1:1 이다

 

 

 

 

2-2 hasMany / belongsTo

 

hasMany
1:N 관계의 두 모델이 있을때, 부모(1) 테이블이 자식(N) 테이블 여러 개에게 참조할 수 있는 속성을 제공하고자 할 때

 

belongsTo
자식 테이블이 부모 테이블을 참조하고자 할 때

 

 

  프로젝트에 적용을 해보겠다 

 

  • 각 유저(User Model)는 여러 개의  게시글(Post Model)을 보유할 수 있다,
  • 유저 모델과  포스트 모델의 관계는 1:N이다. 

 

 

 

.

2-3 belongsToMany

 

belongsToMany
M:N 관계의 두 모델이 있을때, 각 테이블들이 서로에게 참조할 수 있는 속성을 제공하고자 할 때

 

  프로젝트에 적용을 해보겠다

 

  • 각 게시글(Post Model)는 여러 개의  해쉬 태그(Hashtag Model)를 보유할 수 있다,
  • 해쉬태그 역시  해당 해쉬태그에 속한  게시글들을 보유 할 수 있다
  • 따라서 포스트 모델과  해쉬태그 모델은  M:N 이다