아침에 커피숍에 가서 공부하기
오후에는 인터넷에 연결되어 집에서 편안하게 작업했습니다.
그들은 내 목록이라는 유사한 기능이 북마크보다 우선해야 한다고 말했습니다.
나는 새벽까지 내 목록을 코딩하고 구현했습니다.
튜터님의 조언을 듣고 팀원들의 도움을 받으며 많이 배웠습니다.
@Entity()
export class CollectionItem {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne((type) => Collection, (collection) => collection.collectionItems)
@JoinColumn({ name: 'collection_id' })
collection: Collection;
@ManyToOne((type) => Restaurant, (restaurant) => restaurant.collectionItems)
@JoinColumn({ name: 'restaurant_id' })
restaurant: Restaurant;
@ManyToOne((type) => Post, (post) => post.collectionItems)
@JoinColumn({ name: 'post_id' })
post: Post;
}
컬렉션 및 레스토랑 게시물을 CollectionItem이라는 엔터티와 연결하여 다대다 관계를 만들었습니다.
이 정보를 꺼내는 것은 매우 어려웠습니다. 이 부분은 튜터와 팀원들이 도와주었다.
먼저 dto는 컨트롤러에서만 사용할 수 있다는 것을 배웠습니다(서비스에서도 사용할 수 있는지 혼란스러웠습니다).
Swagger를 배웠습니다.
// @UseGuards(AuthGuard('local'))
@Get('/:userId')
@ApiOkResponse({
description: 'MyList 전체조회(해당 유저의 맛집리스트만 불러오기)',
})
@ApiUnauthorizedResponse({ description: '전체조회 실패' })
async getMyLists(@Param('userId') userId: number) {
const myLists = await this.myListService.getMyList(userId);
return await myLists;
}
위와 같이 작성했을 때 자세한 스펙은 localhost:3000/api 에서 볼 수 있어서 프런트와 작업이 수월했습니다.

Nestjs 프로젝트에 Swagger 도입
프로젝트 규모가 커지면 REST API의 수도 크게 늘어납니다. API가 문서화되어 있지 않으면 API가 무엇인지 혼란스러워 여기저기서 소스 코드를 살펴볼 수 있습니다.
velog.io
위의 주소를 참고했는데 쉽고 편리했습니다.
실제 데이터 없이 프런트에서 전달해야 하는 정보에 대한 더미 데이터를 만드는 방법을 배웠습니다.
@Post('/:collectionId')
@ApiOkResponse({
description: 'MyList 포스팅 추가',
})
@ApiUnauthorizedResponse({ description: 'MyList 포스팅 추가 실패' })
async myListPlusPosting(@Param('collectionId') collectionId: number) {
const postId = 1; //<<=== 이부분을 배웠다.
return this.myListService.myListPlusPosting(postId, collectionId);
}
}
사용자 아이디를 알려줘야 하는데 전면이나 UseGuard로 하면 될 것 같은데,
더미 데이터를 전달하여 테스트했습니다.
실제 운영에 필요한 로직을 담당하는 서비스에서 많은 것을 배웠습니다.
async getMyList(userId: number) {
try {
const myLists = await this.collectionRepository.find({
where: { user_id: userId, deletedAt: null, type: 'myList' },
select: { name: true, description: true, image: true },
});
return myLists;
} catch (err) {
console.error(err);
throw new InternalServerErrorException(
'Something went wrong while processing your request. Please try again later.',
);
}
}
where와 select 사용법을 배웠는데 앞으로 코딩할 때 많은 도움이 될 것 같습니다.
async createMyList(userId, name, type) {
try {
return this.collectionRepository.insert({
user_id: userId,
name,
type: 'myList',
});
} catch (err) {
console.error(err);
throw new InternalServerErrorException(
'Something went wrong while processing your request. Please try again later.',
);
}
}
인서트 사용법을 배웠습니다. user_id는 collection entity에 있는 데이터이고 해당 부분에서 받은 userId=1이 전달된다.
async updateMyList(
userId: number,
collectionId: number,
name: string,
image: string,
description: string,
visibility: 'public' | 'private',
) {
try {
// id와 type이 모두 일치하는 Collection 엔티티를 찾는다.
const myList = await this.collectionRepository.find({
relations: {
user: true,
},
});
if (!myList) {
throw new NotFoundException('마이리스트가 없습니다.');
}
await this.collectionRepository.update(
{ id: collectionId },
{
name,
image,
description,
visibility,
},
);
} catch (err) {
if (err instanceof NotFoundException) {
throw err;
} else {
console.error(err);
throw new InternalServerErrorException(
'Something went wrong while processing your request. Please try again later.',
);
}
}
}
이 부분에서는 다대다 관계에서 관계를 사용하여 적절한 사용자 데이터를 얻는 방법을 배웠습니다.
추가적으로 console.error(err); 자세한 오류도 보내라는 조언을 받았습니다.
async deleteMyList(id: number) {
try {
const result = await this.collectionRepository.softDelete(id); // soft delete를 시켜주는 것이 핵심입니다!
if (result.affected === 0) {
throw new NotFoundException('마이리스트가 없습니다.');
}
} catch (err) {
if (err instanceof NotFoundException) {
throw err;
} else {
console.error(err);
throw new InternalServerErrorException(
'Something went wrong while processing your request. Please try again later.',
);
}
}
}
위의 부분에서 피해자에 대해 들었습니다. 코드를 설명하는 GPT 답변을 첨부했습니다.
영향을 받지 않으면 0을 반환합니다.

마지막으로 가장 고민했던 것은 마이리스트 포스트 추가였습니다.
async myListPlusPosting(postId: number, collectionId: number) {
try {
await this.collectionItemRepository.insert({
post: { id: postId },
collection: { id: collectionId },
});
} catch (err) {
if (err instanceof NotFoundException) {
throw err;
} else {
console.error(err);
throw new InternalServerErrorException(
'Something went wrong while processing your request. Please try again later.',
);
}
}
}
}
위의 부분에서 제가 고생한 것이 두 가지 있습니다.
이것은 컬렉션 ID와 게시물 ID를 전달하기 위한 논리입니다.
첫째, 예약 정보를 어떻게 공유해야 합니까? 위의 논리를 따라가기가 너무 쉽지 않나요?
인계받은 팀원이 무언가를 말하는 듯했다. 그래서 나는 그것이 나쁜 직업이라고 생각했습니다.
관계를 설정하고 기여자와 사용자의 실제 정보를 가져오고 이것 저것 함으로써…
튜터의 조언으로 만든 코드인데, 실제로 전달할 데이터를 가져오기가 어려웠습니다.
사실 정답은 다양하지만 통과할 팀원에게 말을 걸어 삽입 기능을 구현했다.
너무 쉬운게 정답이 아니죠? 방탈출 게임에서 이런 일을 여러 번 경험했는데 실제 상황에서는 종종 혼란스럽습니다.
돌아가려고 너무 애썼다. 알고리즘 문제는 매우 쉽게 또는 매우 어렵게 풀 수 있습니다.
const myLists = await this.collectionRepository.find({
relations: {
collectionItems: {
post: true,
},
user: true,
},
where: {
user: {
id: userId,
},
},
});
둘째, 중간 테이블(집합 객체)에 어떻게 값을 입력할 수 있습니까?
await this.collectionItemRepository.insert({
post: { id: postId },
collection: { id: collectionId },
});
@Entity()
export class CollectionItem {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne((type) => Collection, (collection) => collection.collectionItems)
@JoinColumn({ name: 'collection_id' })
collection: Collection;
@ManyToOne((type) => Restaurant, (restaurant) => restaurant.collectionItems)
@JoinColumn({ name: 'restaurant_id' })
restaurant: Restaurant;
@ManyToOne((type) => Post, (post) => post.collectionItems)
@JoinColumn({ name: 'post_id' })
post: Post;
}
시행 착오는 다음과 같습니다
postId:post, post:postId 등이 어떻게 작동하는지 모르기 때문에 모든 것을 시도했습니다.
하지만 팀원 중 한 명이 해결했습니다.
잘은 모르겠지만 그렇게 생각합니다.
우선 엔터티는 post: Post이고 post에는 Post라는 데이터 테이블이 포함되어 있습니다.
그래서 왼쪽에 글을 쓰고 오른쪽에 있는 { id: postId }에 글을 썼습니다.
id는 Post라는 테이블의 ID 값입니다.
받은 postId 값을 적절한 ID 값에 붙여넣습니다.
정확한 개념인지는 모르겠지만 그렇게 생각하니 조금은 마음이 편해졌습니다.
요약하면 정상적으로 작동했고 새벽 2시에 모든 것이 완료되었을 때 오랜만에 기능을 완료했다는 뿌듯함을 느꼈습니다.
![[Java] for반복문을 활용한 [Java] for반복문을 활용한](https://file.thirty30.kr/wp-content/plugins/contextual-related-posts/default.png)
