좋아요 기능 구현 완료 !

·2022년 7월 24일
18

장난감

목록 보기
6/7
post-thumbnail

과거 팀프로젝트에 구현해놨던 것

방금 구현한 좋아요 기능


무슨 문제가 있었어?

내가 구현을 하지 않았지만, 코드를 보고서 어떻게 고쳐야할지 가늠을 잡지 못했다.
프론트에서 해결을 할 수 없냐, 라고 물어봤지만 그 당시에는 작업량이 많아서 건드릴 수 없었고

다들 취업을 하고, 작은 미니프로젝트를 하는 것으로 정리가 되었기에 놔둘 수 밖에 없었다.

그러면서 이번에 미니 프로젝트를 하게 되어 고민을 했다.
아, 좋아요 기능 저번에 내가 구현도 안했고, 어떻게 해야하는거지? 라는 생각이.

해결방법을 찾았다?

해결 방법은 바로 멀리 가지 않고 벨로그에서 찾았다.
좋아요를 광클해도 튀지않고 0101010101이 반복되는 것으로 보아 이것을 벤치마킹하면 되리라 생각했다.

그래서 아래의 글을 작성했었다.

좋아요 기능에 관한 고민중...

그리고 달렸던 댓글에, 이러한 정보가 있었다.

프론트쪽에 코드를 해석해주시는 것도 있었지만, 나는 서버에서 해결하는 것을 원하고 있던 차에 저런 답변을 받을 수 있게 됐다.

FK로 사용하는 두개의 값을 인덱스로 묶어서, 유니크 제약을 사용하면 락이나 트랜잭션 없이 정합성을 유지할 수 있다는 것.

그래서 바로 적용을 해보기 시작했다.

1차 시도(절반 성공)

1차시도는 성공적이였다.
하지만 취소는 할 수 없고 유지가 되는 것으로만 코드를 작성해놨다.

그래서 당연히 저러면 반쪽짜리 기능이라 수정했다.

2차 시도(대실패)

음수로 미친듯이 내려가는 것을 막질 못했다.
로직을 보아하니, 제거하는 로직이 제대로 완성되어있지 못하다는 것을 확인하고 수정을 했다.

3차 시도(대성공)

제대로 기능이 동작하는 것을 확인했다.


사실 고쳐가는 코드를 올렸으면 좋았을텐데, 그런 생각은 하지 못해가지고 남아있진 않다(...)
그래서 과거에 문제가 되었던 코드와, 현재의 코드를 올려놓고 글을 정리하려고 한다!

과거의 제대로 실행이 되지 않았던 코드

 async create({ currentUser, boardId }) {
    const check = await this.boardLikeRepository
      .createQueryBuilder()
      .select('boardLike')
      .from(BoardLike, 'boardLike')
      .where({
        user: currentUser.userId, //
        board: boardId,
      })
      .getOne();

    if (check) {
      await getConnection()
        .createQueryBuilder()
        .update(Board)
        .set({ boardLikeCount: () => `boardLikeCount-1` })
        .where({ boardId })
        .execute();

      await getConnection()
        .createQueryBuilder()
        .delete()
        .from(BoardLike)
        .where({ user: currentUser.userId })
        .execute();

      return `좋아요 -1`;
    }

    await this.boardLikeRepository.save({
      user: currentUser.userId, //
      board: boardId,
    });

    await getConnection()
      .createQueryBuilder()
      .update(Board)
      .set({ boardLikeCount: () => `boardLikeCount+1` })
      .where({ boardId })
      .execute();

    return `좋아요 +1`;
  }

제대로 실행이 되고 있는 현재의 코드

async create(createDiaryLikeInput: CreateDiaryLikeInput): Promise<Diary> {
    const { data, diary } = createDiaryLikeInput;

    const diaryData = await getConnection()
      .createQueryBuilder()
      .select('diary')
      .from(Diary, 'diary')
      .where('diary.id = :id', { id: diary })
      .getOne();

    try {
      if (!diaryData)
        throw new NotFoundException('다이어리가 존재하지 않습니다.');

      // 좋아요 눌렀는지 확인하기
      const alreadyLiked = await this.diaryLikeRepository.findOne({
        where: { fkDiaryId: diary, data },
      });

      if (alreadyLiked) {
        // 좋아요 기록 삭제
        await this.diaryLikeRepository.delete({ id: alreadyLiked.id });

        // 좋아요 카운트 -1
        await getConnection()
          .createQueryBuilder()
          .update(Diary)
          .set({ likeCount: () => `likeCount-1` })
          .where('id = :id', { id: diary })
          .execute();

        // 다이어리 정보 리턴
        return diaryData;
      }

      // 좋아요 기록 생성
      await this.diaryLikeRepository.save({
        fkDiaryId: diary,
        data,
      });

      // 다이어리 좋아요 +1
      await getConnection()
        .createQueryBuilder()
        .update(Diary)
        .set({ likeCount: () => `likeCount+1` })
        .where('id = :id', { id: diary })
        .execute();

      // 다이어리 정보 리턴
      return diaryData;
    } catch (e) {
      if (e.status === 404) {
        return e;
      }
      throw new Error('Diary Like Create Server Error');
    }
  }

Index가 적용되어있는 Entity까지!

import { ObjectType, Field } from '@nestjs/graphql';
import { Diary } from 'src/apis/diary/entities/diary.entity';
import {
  Column,
  CreateDateColumn,
  Entity,
  Index,
  JoinColumn,
  ManyToOne,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';

@ObjectType()
@Entity()
@Index(['fkDiaryId', 'data'], { unique: true })
export class DiaryLike {
  @PrimaryGeneratedColumn('uuid')
  @Field(() => String)
  id: string;

  @Column('uuid')
  @Field(() => String)
  fkDiaryId: string;

  @Column()
  @Field(() => String)
  data: string;

  @ManyToOne((type) => Diary)
  @JoinColumn({ name: 'fkDiaryId' })
  diary: Diary;

  @Column('timestamptz')
  @CreateDateColumn()
  createAt: Date;

  @Column('timestamptz')
  @UpdateDateColumn()
  updateAt: Date;
}

아직은 남은 의문점

어떤 고민을 가지고 있냐면, 저렇게 무한 광클을 하는 사람이 겁내 많다면 어떻게 해야할까? 라는 의문을 가지고 있다.
DB에 엄청난 영향을 줄 것 같은데....

그래서 이런 라이브러리를 적용해놨긴 했다.

그리고, 제일 문제는 그거다.

사람들이 무한으로 광클을 하다보면, 카운트가 +1 -1이 반복할텐데, 그때 팬텀리드였나? 같은게 발생해서 값이 틀어지는 것은 아닐까?
이건 부하테스트를 하던가 해서 검증을 해봐야할 것 같다..


프론트 팀원 : 세상에는 또라이가 많아! 근데 그게 나지(마우스 광클함)
야 좋아요 27개됐는데?

나 : 미친거아닌가진짜

profile
물류 서비스 Backend Software Developer

0개의 댓글