728x90
반응형

기존에 뜨는 맛집리스트라는 기능구현을 했다.

TypeORM으로 기능 구현했는데 그룹화하고, 평균값 구하는 등 많은 일을 하려다보니

find문을 사용한후로 다양한 로직을 구현했다.

 /*
    ### 23.03.20
    ### 표정훈
    ### [Main] 요즘 뜨는 맛집리스트🔥
    */
  async HotMyList() {
    try {
      // 1달 전 날짜를 구한다
      const oneMonthAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);

      // 컬렉션과 게시물, 좋아요 정보를 가져온다
      const myListSumLikes = await this.collectionItemRepository.find({
        relations: {
          post: {
            postLikes: true,
            user: true,
            images: true,
          },
          collection: {
            user: true,
          },
        },
        where: {
          // 컬렉션 타입이 myList 이면서 삭제되지 않은 것을 가져온다
          collection: {
            type: 'myList',
            deletedAt: null,
          },
          post: {
            // 좋아요가 삭제되지 않았고, 1달 이내에 좋아요 업데이트된 게시물만 가져온다
            postLikes: {
              deleted_at: null,
              updated_at: MoreThan(oneMonthAgo),
            },
          },
        },
        select: {
          id: true,
          post: {
            id: true,
            images: { id: true, file_url: true },
            postLikes: {
              id: true,
            },
            user: {
              id: true,
              nickname: true,
            },
          },
          collection: {
            id: true,
            name: true,
            user: {
              id: true,
              nickname: true,
            },
          },
        },
        take: 2,
      });

      // 컬렉션별 좋아요 수를 합산하여 그룹화한다
      const groupedData = myListSumLikes.reduce((groups: any, item: any) => {
        const collectionId = item.collection.id;
        if (!groups[collectionId]) {
          groups[collectionId] = {
            collection: item.collection,
            user: item.collection.user,
            sumLikes: 0,
          };
        }
        groups[collectionId].sumLikes += item.post?.postLikes?.length ?? 0;

        // 게시물에 포함된 이미지 URL 정보를 가져온다
        const images = item.post?.images ?? [];
        const fileUrls = images.map((image: any) => image.file_url);
        groups[collectionId].images = fileUrls;

        return groups;
      }, {});

      // 컬렉션별 좋아요 합산값에 따라 내림차순으로 정렬한다
      const collectionSumLikes: any = Object.values(groupedData);
      collectionSumLikes.sort((a: any, b: any) => b.sumLikes - a.sumLikes);

      // 상위 10개 컬렉션 정보를 구성하여 반환한다
      const top3Collections = collectionSumLikes
        // .slice(0, 10)
        .map(({ collection, user, sumLikes, images }: any) => {
          return {
            id: collection.id,
            name: collection.name,
            user: {
              id: user.id,
              nickname: user.nickname,
            },
            sumLikes,
            images,
          };
        });

      return top3Collections;
    }

그런데 위의 코드는 문제가 있었다. 정보를 가져올때 이미 take로 한정지어서 가져왔기에

뒤에 코드에서 몇개를 분리하든 의미가 없던 것이었다.

결국 쿼리빌더로 작성해봤는데 코드의 양이 엄청나게 줄어들었다.

 

/*
    ### 23.03.20
    ### 표정훈
    ### [Main] 요즘 뜨는 맛집리스트🔥
    */
  async HotMyList() {
    try {
      // 1달 전 날짜를 구한다
      const oneMonthAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000);

      // 컬렉션별로 포스트의 좋아요를 모두 합쳐서 가장 좋아요수가 많은 컬렉션 5개를 순서대로 가져온다
      const top5Collections = await this.collectionItemRepository
        .createQueryBuilder('collectionItem')
        .leftJoinAndSelect('collectionItem.collection', 'collection')
        .leftJoinAndSelect('collection.user', 'user')
        .leftJoinAndSelect('collectionItem.post', 'post')
        .leftJoinAndSelect('post.postLikes', 'postLikes')
        .where('collection.type = :type', { type: 'myList' })
        .andWhere('postLikes.updated_at > :oneMonthAgo', { oneMonthAgo })
        .select([
          'collection.id',
          'collection.name',
          'user.id',
          'user.nickname',
          'user.profile_image',
          'COUNT(postLikes.id) as sumLikes',
        ])
        .groupBy('collection.id')
        .orderBy('sumLikes', 'DESC')
        .limit(5)
        .getRawMany();

      // 상위 5개 컬렉션 정보를 구성하여 반환한다
      const topCollections = top5Collections.map((item: any) => {
        return {
          id: item.collection_id,
          name: item.collection_name,
          user: {
            id: item.user_id,
            nickname: item.user_nickname,
            profile_image: item.user_profile_image,
          },
          sumLikes: item.sumLikes,
        };
      });

      return topCollections;
    }

TypeORM으로만 작성해왔는데

TypeORM 쿼리빌더가 복잡한 로직에는 훨씬 유용한것 같다.

따로 쿼리빌더를 공부해야겠다는 생각이 들었다.

 

 

728x90
반응형

+ Recent posts