독립적으로 데이터들을 만들어 놨는데 사용자가 게시글을 작성한다고 생각해보자.
사용자 한명이 게시글 여러개? 작성할 수 있다. 반대로 게시글 하나에 작성자가 여러명일 수 있을까?
내가 지금 하고 있는 클론프로젝트에서는 불가능하다. 게시글은 한 사람만 쓸 수 있고 그 한사람은 게시글을 여러개 쓸 수 있다.
이 관계를 유저와 포스트간의 일대다 관계(1:N)가 있다라고 한다.
db.Post 어떤 게시글은 어떤 사람한테 속해 있을 수 있다.
그리고 한사람이 게시글을 여러개 쓸 수 있다. 그 댓글은 작성자가 한명이다. 그러면 게시글과 같다고 할 수 있다.
// user.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', { // MYSQL에는 users 테이블 생성
// id가 기본적으로 들어있다.
email: {
// 문자열이여야 하고 30글자 이내여야 한다.
type: DataTypes.STRING(30), // STRING, TEXT, BOOLEAN, INTEGER, FLOAT, DATETIME
allowNull: false, // 필수 true면 선택적
unique: true, // 고유한 값
},
nickname: {
type: DataTypes.STRING(30),
allowNull: false, // 필수
},
password: {
type: DataTypes.STRING(100),
allowNull: false, // 필수
},
}, {
charset: 'utf8',
collate: 'utf_general_ci', // 한글 저장
});
User.associate = (db) => {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
};
return User;
}
// post.js
.....
// 어떤 게시글은 사람한테 속해 있을 것이다.
Post.associate = (db) => {
db.Post.belongsTo(db.User);
};
return Post;
}
comment.js에서도 어떤 댓글은 작성자가 있을 것이다.
module.exports = (sequelize, DataTypes) => {
const Comment = sequelize.define('Comment', { // MySQL에는 comments 테이블 생성
// id가 기본적으로 들어있다.
content: {
type: DataTypes.TEXT, // 글자를 일단 무제한으로 늘려놓자.
allowNull: false,
},
}, {
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci', // 이모티콘 저장
});
Comment.associate = (db) => {
db.Comment.belongsTo(db.User);
};
return Comment;
}
게시글 아래에 댓글이 여러개 달리는데 하나의 댓글에는 게시글이 여러개 있을 수가 없다. 즉 일대다관계(1:N)
// post.js
module.exports = (sequelize, DataTypes) => {
const Post = sequelize.define('Post', { // MySQL에는 posts 테이블 생성
// id가 기본적으로 들어있다.
content: {
type: DataTypes.TEXT, // 글자를 일단 무제한으로 늘려놓자.
allowNull: false,
},
}, {
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci', // 이모티콘 저장
});
Post.associate = (db) => {
db.Post.belongsTo(db.User);
db.Post.hasMany(db.Comment);
};
return Post;
}
여기서 comment.js 아래쪽에 belongsTo는 많은 역할이 있는데 UserId와 postId를 생성해준다.
// comment.js
module.exports = (sequelize, DataTypes) => {
const Comment = sequelize.define('Comment', { // MySQL에는 comments 테이블 생성
// id가 기본적으로 들어있다.
// 게시글이든 사용자든 고유한 아이디가 붙는다.
content: {
type: DataTypes.TEXT, // 글자를 일단 무제한으로 늘려놓자.
allowNull: false,
},
// UserId: 1
// PostId: 3
// 이 두 컬럼을 만들어준다.
}, {
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci', // 이모티콘 저장
});
Comment.associate = (db) => {
db.Comment.belongsTo(db.User);
db.Comment.belongsTo(db.Comment);
};
return Comment;
}
image.js에서는 아래와 같다.
// image.js
module.exports = (sequelize, DataTypes) => {
const Image = sequelize.define('Image', {
// id가 기본적으로 들어있다.
src: {
type: DataTypes.STRING(200),
allowNull: false,
},
}, {
charset: 'utf8',
collate: 'utf8_general_ci', // 이모티콘 저장
});
Image.associate = (db) => {
// 게시글이 1 이미지가 N
db.Image.belongsTo(db.Post);
};
return Image;
}
hashtag는 그러면 어떻게 할까? 게시글 안에 해시태그들이 들어있다. 1대다 관계일까? 해시태그 안에 게시글이 여러개 있을수도 있다. 우리가 인스타그램을 한다고 치면 해시태그를 눌렀다 그러면 해시태그에 속한 게시글들이 쭉 뜬다.
반대로 하나의 게시글도 여러개의 해시태그를 남기는데 즉 다대다 관계이다. belongsToMany를 쓰자.
// post.js
Post.associate = (db) => {
db.Post.belongsTo(db.User);
db.Post.belongsToMany(db.Hashtag);
db.Post.hasMany(db.Comment);
db.Post.hasMany(db.Image);
};
// hashtag.js
module.exports = (sequelize, DataTypes) => {
const Hashtag = sequelize.define('Hashtag', {
// id가 기본적으로 들어있다.
name: {
type: DataTypes.STRING(20),
allowNull: false,
},
}, {
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci', // 이모티콘 저장
});
Hashtag.associate = (db) => {
db.Hashtag.belongsToMany(db.Post);
};
return Hashtag;
}
일대일 관계도 있다. 만약 user가 있고 userInfo가 있다고 하자.
그러면 사용자가 있고 그 사용자에 대한 정보를 다른 테이블에다가 모아놨으면 db.User.hasone(db.UserInfo) / db.UserInfo.belongsTo(db.User) 이렇게 될 것이다.
(사용자와 사용자 정보 1:1 관계)
위에서 belongsToMany를 썼는데 belongsToMany를 그림판으로 설명하면
아래와같이 다대다 관계에서는 중간에 테이블이 하나 생겨서 얘네들이 짝지어지게 된다. 다대다 관계이기 때문에 그림이 아래과 같이 되고 중간테이블이 생성이 되어서 중간테이블을 기준으로 검색이 가능하게 된다.
예를들어 1번테이블에 속해져 있는 hashtable들을 가져와라 그러면 hashtag 1 2번 노드와 리액트르 가져오게되고
2번테이블에 속해있는거 가져와라하면 1번 3번이 가져와지고 3번 테이블에 있는거 가져와라 하면 4번 1번 2번이 가져와지게 된다.
그리고 해시태그를 통해서 게시글들을 가져올 수가 있는데 #노드가 있으면 #노드가 쓰여진 PostId 1 2 3을 가져와 줄수가 있다. 그래서 다대다 관계에는 중간테이블이 필요하고 중간테이블은 Sequelize가 알아서 만들어준다.
좋아요 관계 또한 사용자가 게시글에 좋아요를 누를 수 있고 게시글이 여러명의 사용자로부터 좋아요를 받을 수도 있고 할 수 있다.
// user.js
User.associate = (db) => {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
db.User.belongstoMany(db.Post);
};
return User;
}
// post.js
Post.associate = (db) => {
db.Post.belongsTo(db.User);
db.Post.belongsToMany(db.Hashtag);
db.Post.hasMany(db.Comment);
db.Post.hasMany(db.Image);
db.Post.belongstoMany(db.User);
};
return Post;
중간 테이블의 이름도 정해주자.
// through를 통해서
// user.js
User.associate = (db) => {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
db.User.belongstoMany(db.Post, { through: 'Like' });
};
return User;
post.belongsTo와 post.belongstoMany 두개가 헷갈리므로 as를 넣어서 구분해주자.(나중에 as에 따라서 post.getLikers처럼 게시글 좋아요 누른 사람을 가져오게 된다.)
// post.js
Post.associate = (db) => {
db.Post.belongsTo(db.User); // post의 작성자
db.Post.belongsToMany(db.Hashtag);
db.Post.hasMany(db.Comment);
db.Post.hasMany(db.Image);
db.Post.belongstoMany(db.User, { through: 'Like' }); // post의 좋아요를 누른 사람들
};
return Post;
user.js에서도 마찬가지(별칭은 대문자로 해주는게 좋다.)
// User.js
User.associate = (db) => {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
db.User.belongstoMany(db.Post, { through: 'Like', as: 'Liked' });
};
return User;
같은테이블 간에도(user간에도) 관계가 있을 수 있다. follow 관계가 아래와 같이 다대다 관계로 생긴다. 다대다관계 할때는 중간테이블이 무조건 생긴다. (ex) jay가 팔로잉 하는 사람들을 찾아라 그러면 2 빠니보틀과 3 곽튜브를 찾는다.
그리고 곽튜브의 팔로워를 찾아라 그러면 jay라고 찾게된다.(팔로잉을 찾아라 하면 팔로워부터 시작해서 형성되고
팔로워를 찾아라 그러면 팔로잉부터 시작해서 형성이 된다.)
같은 테이블 내에서 참조관계가 생기면 foreignKey를 넣어준다.(through는 table이름을 바꿔주는 거고 foreignKey는 아예 컬럼의 어떤 id고 어떤 id인지를 바꿔줬다고 생각하면 된다.
// User.js
User.associate = (db) => {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
db.User.belongsToMany(db.Post, { through: 'Like', as: 'Liked' });
db.User.belongsToMany(db.User, { through: 'Follow', as: 'Followers', foreignKey: 'FollowingId' }); // foreignKey부터 시작해서 as의 Followers를 찾는다.
db.User.belongsToMany(db.User, { through: 'Follow', as: 'Followings', foreignKey: 'FollowerId' }); // foreignKey부터 시작해서 as의 Followings를 찾는다.
};
return User;
리트윗도 고려해주자. 한게시글이 여러개시글을 리트윗 할수 있는데 어떤 게시글이 리트윗하면 그 주인이 되는 트윗은 하나다. 그래서 일대다 관계로 형성될 수 있다.
// post.js
Post.associate = (db) => {
db.Post.belongsTo(db.User); // post의 작성자
db.Post.belongsToMany(db.Hashtag);
db.Post.hasMany(db.Comment);
db.Post.hasMany(db.Image);
db.Post.belongsToMany(db.User, { through: 'Like' }); // post의 좋아요를 누른 사람들
// 어떤 게시글의 리트윗 게시글을 구현하자.
// as Retweet으로 해서 PostId에서 Retweet으로 바뀐다.
db.Post.belongsTo(db.Post, { as: 'Retweet' });
};
return Post;
예를 들어 원본게시글이 있다고 하자.
게시글이 맘에 들어서 리트윗을 했다. 그러면 똑같은 게시글들이 생기는데 1:다 관계가 형성됨에 따라 한 게시글이 여러개시글을 리트윗을 하고 리트윗한 게시글은 원본 하나를 가리키고 있다.
즉 아래와 같이 관계가 형성된다고 보면 된다.
<출처 조현영: [리뉴얼] React로 NodeBird SNS 만들기>
[리뉴얼] React로 NodeBird SNS 만들기 - 인프런 | 강의
리액트 & 넥스트 & 리덕스 & 리덕스사가 & 익스프레스 스택으로 트위터와 유사한 SNS 서비스를 만들어봅니다. 끝으로 검색엔진 최적화 후 AWS에 배포합니다., 새로 만나는 제로초의 리액트 노드버
www.inflearn.com
'Node.js > NodeBird(ZeroCho)' 카테고리의 다른 글
Sequelize sync + nodemon 구현 (0) | 2021.11.03 |
---|---|
Sequelize Model 만들기 (0) | 2021.11.02 |
MySQL과 Sequelize 연결하기 (0) | 2021.11.02 |
Express Router 분리하기 (0) | 2021.11.02 |
Express로 Routing하기 (0) | 2021.11.02 |