본 내용은 내일배움캠프에서 활동한 내용을 기록한 글입니다.
인증된(로그인된) 사용자만 사용 가능
상품 게시물의 ID를 req.params
를 통해서 가져옴
사용자 테이블을 통해서 좋아요 테이블에 데이터가 생성됨
data 절에서 현재 테이블과 N:M 관계를 만들 테이블의 id를 connect를 통해 연결하면 됨
오히려 사용자가 중복으로 좋아요 했을 때, 본인이 본인의 게시물에 좋아요를 누를 때와 같은 에러 처리 부분이 더 어려웠음
// 상품 게시글 좋아요 API
tradeRouter.post('/:tradeId/like', accessTokenValidator, async (req, res, next) => {
try {
// 상품 게시글 ID 가져오기
const id = req.params.tradeId;
// 상품 조회하기
const trade = await prisma.trade.findFirst({ where: { id: +id }, include: { likedBy: true } });
// 데이터베이스 상 해당 상품 ID에 대한 정보가 없는 경우
if (!trade) {
return res
.status(HTTP_STATUS.NOT_FOUND)
.json({ status: HTTP_STATUS.NOT_FOUND, message: MESSAGES.TRADE.COMMON.NOT_FOUND });
}
// 사용자 본인의 게시글에는 좋아요 누르지 못하도록 함
if (trade.userId === req.user.id) {
return res
.status(HTTP_STATUS.BAD_REQUEST)
.json({ status: HTTP_STATUS.BAD_REQUEST, message: MESSAGES.TRADE.LIKE.NO_PERMISSION });
}
// 이미 좋아요를 누른 경우
const isDuplicatedLike = trade.likedBy.filter((user) => {
return user.id === req.user.id;
});
if (isDuplicatedLike.length !== 0) {
return res
.status(HTTP_STATUS.BAD_REQUEST)
.json({ status: HTTP_STATUS.BAD_REQUEST, message: MESSAGES.TRADE.LIKE.DUPLICATED });
}
// 사용자가 좋아요를 누르는 로직
const user = await prisma.user.update({
where: { id: req.user.id },
omit: { password: true },
data: {
likedTrade: {
connect: { id: trade.id },
},
},
});
return res.status(HTTP_STATUS.CREATED).json({
status: HTTP_STATUS.CREATED,
message: MESSAGES.TRADE.LIKE.SUCCEED,
data: { tradeId: trade.id, userId: user.id },
});
} catch (err) {
next(err);
}
});
인증된(로그인된) 사용자만 사용 가능
상품 게시물의 ID를 req.params
를 통해서 가져옴
대부분의 코드가 좋아요 기능과 동일함
다른 점은 connect로 연결했던 부분을 disconnect로 수정해주는 것임
// 상품 게시물 좋아요 취소 API
tradeRouter.post('/:tradeId/unlike', accessTokenValidator, async (req, res, next) => {
try {
// 상품 게시물 ID 가져오기
const id = req.params.tradeId;
// 상품 조회하기
const trade = await prisma.trade.findFirst({ where: { id: +id }, include: { likedBy: true } });
// 데이터베이스 상 해당 상품 ID에 대한 정보가 없는 경우
if (!trade) {
return res
.status(HTTP_STATUS.NOT_FOUND)
.json({ status: HTTP_STATUS.NOT_FOUND, message: MESSAGES.TRADE.COMMON.NOT_FOUND });
}
// 사용자 본인의 게시글에는 좋아요 취소 누르지 못하도록 함
if (trade.userId === req.user.id) {
return res
.status(HTTP_STATUS.BAD_REQUEST)
.json({ status: HTTP_STATUS.BAD_REQUEST, message: MESSAGES.TRADE.UNLIKE.NO_PERMISSION });
}
// 이미 좋아요 취소를 누른 경우
const isDuplicatedUnlike = trade.likedBy.filter((user) => {
return user.id === req.user.id;
});
if (isDuplicatedUnlike.length === 0) {
return res
.status(HTTP_STATUS.BAD_REQUEST)
.json({ status: HTTP_STATUS.BAD_REQUEST, message: MESSAGES.TRADE.UNLIKE.NOT_LIKE });
}
// 사용자가 좋아요 취소를 누르는 로직
const user = await prisma.user.update({
where: { id: req.user.id },
omit: { password: true },
data: {
likedTrade: {
disconnect: { id: trade.id },
},
},
});
return res.status(HTTP_STATUS.CREATED).json({
status: HTTP_STATUS.CREATED,
message: MESSAGES.TRADE.UNLIKE.SUCCEED,
data: { tradeId: trade.id, userId: user.id },
});
} catch (err) {
next(err);
}
});
Q. 슬랙의 모든 기능들을 나열하기
Q. 워크스페이스 회원 관리의 경우의 수를 여러분들이 구현해야 된다고 하면 어떻게 구현하시겠습니까? 구현 로직을 상세히 설명해주세요.
명예의 전당 과제 도전하기
상수 객체 구조 변경으로 인한 에러 수정하기
API 명세서 수정하기
배포 테스트하기
오늘은 게시물 좋아요 기능 구현을 통해 N:M 관계를 구현하는 방법에 대해서 알게 됨
그래도 다행히 초반에 N:M 관계에 대한 스키마를 잘 정의해서 구현하기 용이했음
N:M 관계에서 생성된 암시적 테이블은 connect, disconnect 쿼리를 통해서 관계를 연결하고 끊는 작업을 함
그저 connect 쿼리로 관계를 연결해주기만 하면 자동으로 암시적 테이블에 데이터가 들어감
그리고 게시물 목록, 상세 조회에서는 좋아요의 수가 보여야 하기 때문에 계속을 방법을 찾았음
찾아보니 생각보다 간단하게 구현됨
_count, _sum, _avg 등 실제 Raw 쿼리에서 사용하던 쿼리가 존재했음
이번에는 _count 쿼리를 이용해서 생각보다 손 쉽게 N:M 관계의 요소의 개수를 구함
기존에 단순히 임의의 like 값으로 정렬을 함
하지만 좋아요 기능이 구현되어 좋아요를 카운트 하는 방법을 찾고 있었음
include 절을 통해서 likedBy라는 관계 변수도 포함해서 상품 목록을 가져왔음
하지만 정렬의 컨디션을 정하기 위한 조건문은 상품 목록을 찾는 쿼리보다 먼저 실행되어야 했음
그래서 조건을 어디에 어떻게 작성해야 할지 도저히 감도 잡히지 않았음
계속 찾다보니 Prisma에서 _count 라는 쿼리를 지원한다는 것을 찾음
// 상품 게시물 목록 조회 API (뉴스피드)
tradeRouter.get('/', async (req, res) => {
// 정렬 조건 쿼리 가져오기
let sortDate = req.query.sort?.toLowerCase();
let sortLike = req.query.like?.toLowerCase();
let type; // 쿼리 orderBy 조건을 담을 변수
// like 정렬 쿼리가 있으면 좋아요 순으로 정렬
if (sortLike) {
// 시간 순 정렬 기본 값 설정
if (sortLike !== SORT.desc && sortLike !== SORT.asc) {
sortLike = SORT.desc;
}
// 같은 좋아요가 있는 경우 최신순으로 정렬
type = [{ likedBy: { _count: sortLike } }, { createdAt: SORT.desc }];
} else {
// 좋아요 순 정렬 기본 값 설정 (상세한 내용은 회의가 필요)
if (sortDate !== SORT.desc && sortDate !== SORT.asc) {
sortDate = SORT.desc;
}
type = { createdAt: sortDate };
}
// trade 테이블의 데이터 모두를 조회
let trades = await prisma.trade.findMany({
include: { tradePicture: true, user: true, likedBy: true },
orderBy: type,
omit: { content: true },
});
trades = trades.map((trade) => {
return {
id: trade.id,
userId: trade.user.id,
title: trade.title,
price: trade.price,
region: trade.region,
like: trade.likedBy.length,
createdAt: trade.createdAt,
updatedAt: trade.updatedAt,
tradePicture: trade.tradePicture.map((img) => img.imgUrl),
};
});
return res
.status(HTTP_STATUS.OK)
.json({ status: HTTP_STATUS.OK, message: MESSAGES.TRADE.READ.SUCCEED, data: { trades } });
});
생각보다 너무 쉽게 해결되어서 허탈했지만, 또 이렇게 하나를 배운다고 생각함
참고 자료는 다음과 같음