본문 바로가기
띡딱똑띡 개발자 Hanna

NodeJS와 MongoDB로 SNS 만들어보기 - user_ment (댓글/대댓글 라우터)

by HannaDev 2019. 11. 15.

2019/11/14 - [띡딱똑띡 개발자 Hanna] - NodeJS와 MongoDB로 SNS 만들어보기 - user_postingPlus (게시글 라우터2)

 

NodeJS와 MongoDB로 SNS 만들어보기 - user_postingPlus (게시글 라우터2)

2019/11/14 - [띡딱똑띡 개발자 Hanna] - NodeJS와 MongoDB로 SNS 만들어보기 - user_posting (게시글 라우터) NodeJS와 MongoDB로 SNS 만들어보기 - user_posting (게시글 라우터) 2019/11/14 - [띡딱똑띡 개발자..

granora2019.tistory.com

ㄴ 이전 글

 

더보기

생각해보니 라우터 목록 정리처럼 데이터 스키마 구조도 하나씩 정리하는게 좋을 것 같네요 ㅎㅎ...

 

점점 써야될게 많아지고...

 


 

routes 폴더 구조


 

 

* 현재까지 설명한 router => 7번 (user_passport), 10번 (user_profile), 4번 (user_follow),

                                            8번 (user_posting), 9번 (user_postingPlus)

 

* 현재 설명하고자 하는 router => 6번 (user_ment)

 

 

 

> user_postingPlus

 

user_ment.js 파일 내의 라우터 목록

 

user_ment.js는 댓글 관련 라우터들을 정의한 파일입니다.

댓글/대댓글 수정은 굳이 넣지 않았습니다. (수정 원하면 삭제하고 다시 쓰는걸로 ^^...)

 

또한 기획 상 대댓글이 존재하는 댓글 삭제 시,

댓글을 삭제하는 것이 아닌 "삭제된 댓글입니다." 라는 문구로

댓글 내용이 바뀌도록 했습니다.

 


댓글은 그 형태에 따라 구현방법이 여러가지 있을 것 같은데,

만약 댓글, 대댓글, 대대댓글, 대대대댓글 ... 처럼 무한정으로 답글을 달 수 있는

구조라면 아래와 같이 댓글 스키마를 계층적으로 구성하여 구현하면 됩니다.

(무한 댓글, 계층형 댓글 등의 키워드로 검색하면 많이 나오니

 만약 무한 댓글을 구현하고자 할 시 참고하시면 될 것 같습니다.)

 

https://forest71.tistory.com/51?category=562155

 

1. 무한 댓글 시작하기

댓글에 대한 댓글을 작성하는 것을 무한 댓글, 계층형 댓글, 대댓글 이라고 한다. 이 무한 댓글을 개발하기 위해서는 3가지 필드가 필요하다. 먼저, 부모를 표시하는 필드(reparent), 현재 댓글이 게시물을 기준으..

forest71.tistory.com

https://ssmlim.tistory.com/7

 

[DB] 계단형 게시판 DB구조

※공부하는 겸 쓰는 글입니다 잘못된 정보가 있다면 댓글로 지적해주세요! 계단형 게시판의 예 (사진은 아라공 CCNA 덤프게시판) 흔히 계단형 게시판이라면 위에처럼 생긴 것을 말한다. 계단형 게시판은 일반 데..

ssmlim.tistory.com

 


 

하지만 CatcherLand 프로젝트에서는 스마트폰 앱 내의 SNS 기능을 구현하고자하는 것이므로

보편적이고 심플하게 '댓글' + '대댓글' 형태로만 구현하기로 했습니다. (유튜브 댓글 느낌으로!)

따라서 굳이 위와 같이 계층 구조로 스키마를 구성할 필요가 없기 때문에

'댓글 스키마''대댓글 스키마'스키마를 분리하였습니다.

 

 

2019/11/10 - [띡딱똑띡 개발자 Hanna] - NodeJS와 MongoDB로 SNS 만들어보기 - 데이터 스키마 구조

 

NodeJS와 MongoDB로 SNS 만들어보기 - 데이터 스키마 구조

현재 MongoDB (NoSql)를 사용하고 있지만 Mongoose를 활용해 데이터 스키마를 정의해 데이터를 생성하고 접근하고 있습니다. 다음은 SNS 기능 구현을 위해 현재까지 작성한 데이터 스키마들과 데이터 스키마들 간..

granora2019.tistory.com

ㄴ 이전 포스트 중 데이터 스키마 구조 형태를 정리해놓은 포스트가 있는데,

    해당 포스트에서 댓글, 대댓글 스키마를 나눈 모습을 확인하실 수 있을 것입니다.

    간략하게 댓글, 대댓글 스키마에 한해 설명을 드리자면 다음과 같습니다.

 

< UpmentScheme > - 댓글 스키마

 

_id : 댓글의 ObjectId

post_id : 부모 게시판의 ObjectId

writer_id : 작성자의 ObjectId

ㄴ 위 3개의 ObjectId 값을 기준으로

    다른 테이블 (유저, 게시판 등)을

    참조하거나 참조당하거나 합니다.

text : 댓글 내용

count.comment_count : 소속 대댓글 수

count.like_count : 좋아요 수

count.complain_count : 신고 수 

created_at : 작성일

 

< DownmentScheme > - 대댓글 스키마

 

_id : 대댓글의 ObjectId

post_id : 부모 게시판의 ObjectId

parent_id : 부모 댓글의 ObjectId

text : 댓글 내용

count.like_count : 좋아요 수

count.complain_count : 신고 수 

created_at : 작성일

 

 

 

 

한가지 포인트가 있다면 댓글/대댓글 스키마 두 곳에 모두 post_id 값이 존재한다는 것인데요.

post 삭제 시, 소속 댓글/대댓글이 모두 삭제되야하는데 이 때 좀 더 간단하게 삭제하기 위해서입니다.

 

[1] 만약 댓글 스키마에만 post_id 값이 존재한다면 post 삭제 시

아래와 같이 댓글 테이블에 접근했다가 대댓글 테이블에 또 접근해야 합니다.

 

=> "삭제하고자하는 게시글의 _id값을 갖는 댓글을 댓글 테이블에 접근해서 찾음."

=>   해당 댓글 _id 값을 변수에 저장 (A)

=> "해당 댓글들의 _id값을 갖는 대댓글을 대댓글 테이블에 접근해서 삭제"

=> "삭제하고자하는 게시글의 _id값을 갖는 댓글을 댓글 테이블에 접근해서 삭제"

        or "(A) 에 해당하는 _id값을 갖는 댓글을 댓글 테이블에 접근해서 삭제"

 

[2] 하지만 대댓글에서 post_id값이 존재한다면 삭제 시,

아래와 같이 독립적으로 두 테이블에 접근해서 처리할 수 있게 됩니다.

 

=> "삭제하고자하는 게시글의 _id값을 갖는 댓글을 댓글 테이블에 접근해서 삭제"

=> "삭제하고자하는 게시글의 _id값을 갖는 대댓글을 대댓글 테이블에 접근해서 삭제"

 

Node.js는 비동기적으로 함수들이 진행되는만큼

독립적으로 두 테이블에 접근해서 처리하는 것이 더 빠르고 효율적이라고

생각됐고, 코드적으로도 [2] 와 같이 구현하는게 간편하기 때문에

[2] 와 같은 흐름으로 처리했습니다.

 


 

function_ment.js 파일 내의 함수 목록

const COUNTTYPE = Object.freeze({
    'Post': 1,
    'Upment': 0
});

var updateCount = function (database, isAdd, type, ID, callback) { ... }

var getMent = function (database, isUpment, mentId, callback) { ... }

var removeMent = function (database, isUpment, ment, callback) { ... }

module.exports = {COUNTTYPE, updateCount, getMent, removeMent};

function_ment.js 코드 구조는 위와 같은데 exports.(함수이름) = function (...) { ... } 처럼 함수들을

추출했었는데 module.exports = {변수들} 해도 모듈화되더라구요. 그래서 그렇게 해봤습니다. ㅎㅎ;;

 

전과 마찬가지로 COUNTTYPE (enum) 을 선언해 사용하고 있습니다.

 


 

 

* Router 상세 정보 *

더보기

POST     /getUpMents

* 최근 댓글 목록

 

>> 필요 파라미터 <<

{

  postId : 부모 게시글의 ObjectId (String),

  page : 페이지 번호 (int),

  ㄴ 코드 상에서는 1페이지인가 아닌가만 체크하긴합니다.

  ㄴ 첫 페이지인 경우 '1'로 보내주세요!

  lastDate : 그 전 페이지 마지막 댓글의 작성일 (String)

  ㄴ 첫 페이지인 경우 '0'으로 보내주세요!

}

 

> 에러 발생 시

{

  isGetMent: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isGetMent: true (boolean),

  ments: [{ _id: 댓글의 ObjectId (String),

              w_id: 작성자의 ObjectId (String),

              w_nickname: 작성자의 닉네임 (String),

              w_userName: 작성자의 아이디 (String),

              w_isBasicImg: 작성자의 프로필 이미지가 기본 프로필 이미지인지 (boolean),

              w_cloudUrl: 작성자 프로필 이미지 Url (String),

              ㄴ w_isBasicImg가 true인 경우 null 값이 반환됩니다.

              like_count: 댓글에 눌린 좋아요 수 (int),

              comment_count: 댓글에 달린 대댓글 수 (int),

              text: 댓글 내용 (String),

              created_at: 작성일자 (String),

              isLike: 로그인되어있을 시, 해당 댓글 좋아요 여부 (boolean),

              isMyment: 로그인되어있을 시, 내 댓글인지 여부 (boolean)

             }], <= 댓글 목록 리스트 (로그인 안되어있을시, isLike=isMyment=false)

  remainPage: 남은 페이지 수 (int),

  totalNum: 남은 목록 수 (int)

  ㄴ totalNum값이 0이면 더이상 조회할 데이터가 없는 상태인 것입니다.

}

 

 

 

 

 

POST    /getDownMents

* 최근 대댓글 목록

 

>> 필요 파라미터 <<

{

  postId : 부모 게시글의 ObjectId (String),

  parentId : 부모 댓글의 ObjectId (String),

  page : 페이지 번호 (int),

  ㄴ 코드 상에서는 1페이지인가 아닌가만 체크하긴합니다.

  ㄴ 첫 페이지인 경우 '1'로 보내주세요!

  lastDate : 그 전 페이지 마지막 댓글의 작성일 (String)

  ㄴ 첫 페이지인 경우 '0'으로 보내주세요!

}

 

> 에러 발생 시

{

  isGetMent: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isGetMent: true (boolean),

  ments: [{ _id: 대댓글의 ObjectId (String),

              w_id: 작성자의 ObjectId (String),

              w_nickname: 작성자의 닉네임 (String),

              w_userName: 작성자의 아이디 (String),

              w_isBasicImg: 작성자의 프로필 이미지가 기본 프로필 이미지인지 (boolean),

              w_cloudUrl: 작성자 프로필 이미지 Url (String),

              ㄴ w_isBasicImg가 true인 경우 null 값이 반환됩니다.

              like_count: 대댓글에 눌린 좋아요 수 (int),

              text: 대댓글 내용 (String),

              created_at: 작성일자 (String),

              isLike: 로그인되어있을 시, 해당 대댓글 좋아요 여부 (boolean),

              isMyment: 로그인되어있을 시, 내 대댓글인지 여부 (boolean)

             }], <= 대댓글 목록 리스트 (로그인 안되어있을시, isLike=isMyment=false)

  remainPage: 남은 페이지 수 (int),

  totalNum: 남은 목록 수 (int)

  ㄴ totalNum값이 0이면 더이상 조회할 데이터가 없는 상태인 것입니다.

}

 

 

 

 

   

POST    /writeUpMent

* 댓글 작성

 

>> 필요 파라미터 <<

{

  postId : 부모 게시글의 ObjectId (String),

  TEXT : 댓글 내용 (String)

  ㄴ 댓글 길이는 1자~200자여야 합니다.

}

 

> 에러 발생 시

{

  isUpMent: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isUpMent: true (boolean)

}

 

 

 

 

 

POST    /writeDownMent

* 대댓글 작성

 

>> 필요 파라미터 <<

{

  postId : 부모 게시글의 ObjectId (String),

  parentId : 부모 댓글의 ObjectId (String),

  TEXT : 대댓글 내용 (String)

  ㄴ 대댓글 길이는 1자~200자여야 합니다.

}

 

> 에러 발생 시

{

  isDownMent: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isDownMent: true (boolean)

}

 

 

 

 

 

GET     /removeUpment/:upmentId

* 댓글 삭제

 

>> 필요 파라미터 (링크 뒤에 붙여서 보내주세요!) <<

{

  upmentId : 해당 댓글의 ObjectId (String)

}

 

> 에러 발생 시

{

  isRemoveUpment: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isRemoveUpment: true (boolean)

}

 

 

 

 

 

 

GET     /removeDownment/:downmentId

* 대댓글 삭제

 

>> 필요 파라미터 (링크 뒤에 붙여서 보내주세요!) <<

{

  downmentId : 해당 대댓글의 ObjectId (String)

}

 

> 에러 발생 시

{

  isRemoveDownment: false (boolean),

  errorMsg: 에러 메세지 (String)

}

 

> 정상 작동 시

{

  isRemoveDownment: true (boolean)

}

 

 

ㄴ 프론트(Flutter)를 위한 라우터 상세 정보 입니다.

 

 

 

 

 

 

 

 

 

댓글