체인의정석

TypeORM & NestJS) Query Selector 사용하여 다수의 데이터를 가져오고 Response 구조로 다수의 데이터 응답 보내기 본문

개발/backend

TypeORM & NestJS) Query Selector 사용하여 다수의 데이터를 가져오고 Response 구조로 다수의 데이터 응답 보내기

체인의정석 2021. 11. 3. 15:10
728x90
반응형

다음과 같이 queryBuilder를 사용하면 find() 를 사용할 때보다 더 자유로운 검색이 가능하다.

 

먼저 getRepository 에는 테이블 이름이 들어가게 되는데 이 테이블은 entites 폴더 안의 dto에 정의를 해둔다.

해당 dto는 데이터베이스와 완전히 똑같은 구조로 정의를 해준다.

 

이때 계속해서 에러가 나는 부분이 바로 이 entity에 없는 값이라고 에러가 도출되는 부분이였다.

 

계속해서 해메다가 공식문서를 다시 찾아보게 되었고. 

https://typeorm.io/#/select-query-builder/

 

TypeORM - Amazing ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server,

 

typeorm.io

getOne() => 하나의 값을 도출

getMany() => 여러개의 값을 도출

 

을 통해 일차적으로 다중 결과값을 처리해 주었다.

 

또한 여기서 select에 sum 이나 max 같은 연산을 하여 새로운 칼럼을 추가해 주었으므로,

getRawOne() 이다 getRawMany()로 변경해 주어야한다는 사실을 알아서 변경을 해주었다.

 

그 결과 값이 제대로 도출됨을 확인할 수 있었다.

      const transactions = await getRepository(칼럼이름)
        .createQueryBuilder()
        .select('from_address')
        .addSelect('to_address')
        .addSelect('COUNT(*)', 'totalTxCount')
        .addSelect('SUM(value)', 'sumValue') // 왼쪽은 계산 식 오른쪽은 alias
        .addSelect('MAX(block_timestamp)', 'maxTimestamp') //addSelect를 다음과 같이 써서 다중 select 가능
        .addSelect('MIN(block_timestamp)', 'minTimestamp')
        .where('from_Address = :from_address', {
          from_address: from_address, //where 조건절 추가
        })
        .groupBy('to_address')
        .orderBy('value', 'DESC')
        .skip(page) //OFFSET : 응답개수 카운트가 시작되는 지점
        .take(rpp)	//LIMIT : 한번에 응답하는 숫자의 총합
        .printSql() // sql 테스트를 위해 프린트 해보기
        .getRawMany(); // getMany를 하게 되면 entity와 같은 값만 나옴, rawMany를 해야 위와 같은 연산 처리가 가능하다.

 

이후에 이러한 값들을 response class로 객체화 시켜서 리턴하여 주기 위하여서 아래와 같이 각각 forEach 문을 돌면서 결과 값을 push해서 리턴해 주었다. 처음에는 map을 써서 push까지 한번에 하려 하였으나. 연산하여 모두 적용하는 것이 아니라 원래 트랜잭션 결과 값을 그대로 받아오는 것이였기 때문에 forEach를 사용하였다.

      transactions.forEach((x) => {
        const obj: RelatedTransactionsData = {
          fromAddress: x.from_address,
          toAddress: x.to_address,
          totalTxCount: x.totalTxCount,
          sumValue: x.sumValue,
          maxTimestamp: x.maxTimestamp,
          minTimestamp: x.minTimestamp,
        };
        responseDataArr.push(obj);
      });

이렇게 나온 responseDataArr을 response 객체안의 data에 넣어준다. 

 

이렇게 여러개의 data가 나올 때는 해당 data의 총합이 몇개인지 찾아서 구해주는 식도 추가해주는 것이 좋다는 피드백을 받았다.

 

따라서 다음과 같이 구성하였다.

export class SearchByValueData {
  @IsString()
  hash: string;
  @IsEthereumAddress()
  fromAddress: string;
  @IsEthereumAddress()
  toAddress: string;
  @IsNumber()
  value: number;
  @IsString()
  blockTimeStamp: string;
}

export class SearchByValueDataResponse extends CommonResponseData {
  items: SearchByValueData[];
}
export class SearchByValueResponse extends CommonResponse {
  @IsNumber()
  code: number;
  messege?: string;
  data?: SearchByValueDataResponse;
}

위와 같은 방식으로 진행하면, 응답에 대한 값을 더 체계적으로 줄 수 있다.

 

여기서 Common Response와 CommonResponseData의 경우 상위 폴더로 빼서 더 간결하게 코드를 작성하였다.

import { IsNumber } from 'class-validator';

export class CommonResponse {
  code: number;
  message?: string;
}

export class CommonResponseData {
  @IsNumber()
  count?: number;
}

다음과 같이 작성하여 여러개에 대한 결과값의 수와 데이터를 각각 리턴해 주는식으로 만들었다.

 

이렇게 다수의 데이터를 조회하고 리턴하는 구조를 한번 작성해 봤다.

 

 

728x90
반응형
Comments