😎 결과
2022-09-02.3.47.19.mov
💭 내 생각
좋아요를 구현하는 것은 생각보다 어려웠다.
처음에는 forum, comment 모델 안에 heart 필드를 넣어두었는데,
결국은 하트를 모델로 따로 분리하고
forum, comment 에서 aggregate > $lookup 으로 하트를 조인하는 것으로 변경했다.
왜냐하면 이게 훨씬 더 깔끔해 보였기 때문이다.
🔑 작업과정
백엔드
1. heart model
하트모델은 유저 ObjectId, 게시물 ObjectId, 댓글 ObjectId 필드로 구성하였다.
const heartSchema = new Schema ( {
_user : {
type : mongoose . Schema . Types . ObjectId ,
ref : 'User' ,
required : true
} ,
_forum : {
type : mongoose . Schema . Types . ObjectId ,
ref : 'Forum'
} ,
_comment : {
type : mongoose . Schema . Types . ObjectId ,
ref : 'Comment'
} ,
} )
2. heart controller
하트는 update, delete controller 만 만들었다.
updateHeart
=> 유저가 하트를 클릭할 때 작동한다.
하트가 있을 경우 => 타겟 하트 db 삭제, fixHeartCount: -1, heartFill: false 응답
하트가 없을 경우 => 타겟 하트 db 생성, fixHeartCount: +1, heartFill: true 응답
deleteHearts
=> 유저가 게시물이나 댓글을 삭제할 경우 작동한다.
게시물을 삭제할 경우 => 타겟 게시물 id를 가진 하트 db 모두 삭제
댓글을 삭제할 경우 => 타겟 댓글 id 가진 하트 db 모두 삭제
const updateHeart = async ( req , res ) => {
const _user = req . user . id ;
const _comment = ( req . body . _comment ? req . body . _comment : null ) ;
const _forum = req . body . _forum ; // forum id 반드시 필요
const data = { _user, _comment, _forum } ;
try {
const heart = await Heart . findOne ( {
$and : [
{ _user : _user } , { _comment : _comment } , { _forum : _forum }
]
} )
if ( heart ) {
await heart . delete ( )
res . status ( 200 ) . json ( {
fixHeartCount : - 1 ,
heartFill : false ,
msg : 'heart -1'
} )
} else {
const newHeart = new Heart ( data ) ;
await newHeart . save ( )
res . status ( 200 ) . json ( {
fixHeartCount : + 1 ,
heartFill : true ,
msg : 'heart +1'
} )
}
} catch ( err ) {
console . log ( err )
res . status ( 400 ) . json ( err )
}
}
const deleteHearts = async ( req , res , next ) => {
const _comment = ( req . _comment ? req . _comment : null ) ;
const _forum = ( req . _forum ? req . _forum : null ) ;
try {
await Heart . deleteMany ( ( _comment ? { _comment : _comment } : { _forum : _forum } ) )
if ( _comment === null ) {
next ( ) ;
} else {
res . status ( 200 ) . json ( 'Comment, Hearts deleted' )
}
} catch ( err ) {
console . log ( err )
res . status ( 400 ) . json ( {
error : true ,
msg : 'Server Error'
} )
}
}
3. heart router
heart delete controller 는 forum delete / comment delete controllers 에서 next() 로 연결하였다.
router . post ( '/update' , auth , updateHeart ) ;
프론트
1. updateHeart
forumList, commentList, forumView
=> 타겟 인덱스를 찾아 heartCount, heartFill 만 수정하여 바로 업데이트한다.
// 예시 forumList.tsx
const updateHeart = async ( e : BtnMouseEventType , forumId : Types [ 'forumId' ] ) => {
e . preventDefault ( ) ;
const body = {
_forum : forumId ,
}
Hearts . postHeart ( body )
. then ( ( data ) => {
let newForums = [ ...forums ] ;
const findIndex = forums . findIndex ( el => el . forumId == forumId ) ;
const newHeartCount = forums [ findIndex ] . heartCount + data . fixHeartCount ;
const newHeartFill = data . heartFill ;
if ( findIndex !== - 1 ) {
newForums [ findIndex ] = {
...newForums [ findIndex ] ,
heartCount : newHeartCount ,
heartFill : newHeartFill
} ;
if ( selectValue === 'whatILike' ) {
newForums = newForums . filter ( forum => forum . heartFill === true ) ;
} else if ( selectValue === 'heartOrder' ) {
newForums = newForums . sort ( ( a , b ) => b . heartCount - a . heartCount )
}
setForums ( newForums )
}
} )
. catch ( ( err ) => {
console . log ( err ) ;
} )
}
😎 결과
2022-09-02.3.47.19.mov
💭 내 생각
좋아요를 구현하는 것은 생각보다 어려웠다.
처음에는 forum, comment 모델 안에 heart 필드를 넣어두었는데,
결국은 하트를 모델로 따로 분리하고
forum, comment 에서 aggregate > $lookup 으로 하트를 조인하는 것으로 변경했다.
왜냐하면 이게 훨씬 더 깔끔해 보였기 때문이다.
🔑 작업과정
백엔드
1. heart model
하트모델은 유저 ObjectId, 게시물 ObjectId, 댓글 ObjectId 필드로 구성하였다.
2. heart controller
하트는 update, delete controller 만 만들었다.
updateHeart
=> 유저가 하트를 클릭할 때 작동한다.
deleteHearts
=> 유저가 게시물이나 댓글을 삭제할 경우 작동한다.
3. heart router
heart delete controller 는 forum delete / comment delete controllers 에서 next() 로 연결하였다.
프론트
1. updateHeart
forumList, commentList, forumView
=> 타겟 인덱스를 찾아 heartCount, heartFill 만 수정하여 바로 업데이트한다.