만들고 싶은 데이터 구조

{
  'year' : { 
    '2023' : { 'Back' : [ 10, 30, 40, ,,,],...}, 
    '2024' : { ...}
  }
}

 

 

타입을 정의하여 구현 하기

// TypeScript에서 객체의 키와 값이 동적으로 설정될 수 있도록 문법
// index signiture 를 이용
class ExerciseDataDTO {
  [bodyPart: string]: number[];
}

class YearlyDataDTO {
  [year: number]: ExerciseDataDTO;
}


export class AggregatedResultDTO {
  year: YearlyDataDTO;

  constructor() {
    this.year = {};
  }
}

https://joey0203.tistory.com/369 에서 내용 추가.

 

장점

  • 객체가 변경되지 않으므로 예측가능한 상태 유지 가능
  • 이해하기 쉽고 안정적인 서비스 개발에 도움이 된다.

 

단점

  • 객체의 값이 할당될 때마다 새로운 객체가 필요하다.

 

구현 방법

const 사용

const helloWorld = "Hello World";

helloWorld = "Hi world"; // Cannot assign to 'helloWorld' because it is a constant.

 

Object.freez() 이용

const myDefinitelyConstantObject = Object.freeze({
  msg: "Hello World",
});

// Cannot assign to 'msg' because it is a read-only property.
myDefinitelyConstantObject.msg = "Hi"


const myFrozenArray = Object.freeze(["Hi"]);

//Property 'push' does not exist on type 'readonly string[]'.
myFrozenArray.push("World");

 

readonly 이용

class UserDetails { 
        readonly name: string 
        readonly city: string 
        readonly phoneNo: number 
        constructor(name: string, city: string, phoneNo: number){ 
            this.name = name 
            this.city = city 
            this.phoneNo = phoneNo 
        }   
} 
      
const user1 = new UserDetails("ABCD", "XYZ", 1234567890); 
const user2 = new UserDetails("APPLE", "PQR", 1269785100);

 

 

 

 

참고자료

'프로그래밍 > TypeScript' 카테고리의 다른 글

[TS] index signature  (0) 2024.08.03
[ TS ] DTO object 구현  (0) 2024.08.03
[ TS ] 비밀번호 암호화 (bcypt)  (0) 2024.06.13
[ TS ] tsconfig.json 의 내용 정리  (0) 2024.06.08
[ TS ] 오버로딩  (0) 2024.05.09

실험 환경

Nest.js, TypeORM , MySQL, TypeScript,

 

코드

// soft delete
async softDeleteUser(users: User[]) {
    const userIds = users.map((user) => user.id);
    const startTime = Date.now();
    await this.userRepository.softDelete({ id: In(userIds) });
    const duration = Date.now() - startTime;
    this.logger.log(
      `(softDelete) Bulk update of ${userIds.length} users completed in ${duration}ms`,
    );
  }

// createQueryBuilder
  async softDeleteUserCreateQuery(users: User[]) {
    const userIds = users.map((user) => user.id);
    const startTime = Date.now();
    await this.userRepository
      .createQueryBuilder()
      .softDelete()
      .where('id IN (:...userIds)', { userIds })
      .execute();
    const duration = Date.now() - startTime;
    this.logger.log(
      `(createQueryBuilder) Bulk update of ${userIds.length} users completed in ${duration}ms`,
    );
  }

 

Postman 으로 실험해본 결과

 

이용 방식 1차 속도  2차 속도
softDelete 39 37
createQuery 37 39

 

결론

두 방식다 비슷한 속도를 보인다. 상황에 맞게 softDelete 와 createQuery 를 선택해서 사용하면 되겠다.

실험 환경

Nest.js, TypeORM , MySQL, TypeScript,

 

코드

1. update method

  async updateUsersNames(users: User[]) {
    const startTime = Date.now();
    for (const user of users) {
      await this.userRepository.update(user.id, user);
    }
    const duration = Date.now() - startTime;
    this.logger.log(
      `(update method) Bulk update of ${users.length} users completed in ${duration}ms`,
    );
  }

 

2.  createQueryBuilder method

 async updateUsersNamescreateQueryBuilder(users: User[]) {
    const startTime = Date.now();
    for (const user of users) {
      await this.userRepository
        .createQueryBuilder()
        .update(User)
        .set({ name: user.name })
        .where('id = :id', { id: user.id })
        .execute();
    }
    const duration = Date.now() - startTime;
    this.logger.log(
      `(createQueryBuilder) Bulk update of ${users.length} users completed in ${duration}ms`,
    );
  }

 

3. query 작성방식

 async updateUserNamesQuery(users: User[]) {
    const startTime = Date.now();
    const values = users
      .map((user) => `(${user.id}, ${user.name}, ${user.email})`)
      .join(', ');
    const query = `
        INSERT INTO user (id, name, email)
        VALUES ${values} as new
        ON DUPLICATE KEY UPDATE
          id = new.id,
          name = new.name,
          email = new.email,
      `;
    await this.userRepository.query(query);
    const duration = Date.now() - startTime;
    this.logger.log(
      `(query) Bulk update of ${users.length} users completed in ${duration}ms`,
    );
  }

 

4. save method

 async updateUsersNamesSave(users: User[]) {
    const startTime = Date.now();
    const values = users.map((user) => {
      const newUser = new User({ name: user.name, email: user.email });
      newUser.id = user.id;
      return newUser;
    });
    await this.userRepository.save(values);
    const duration = Date.now() - startTime;
    this.logger.log(
      `(save) Bulk update of ${users.length} users completed in ${duration}ms`,
    );
  }

 

 

Postman 으로 한번에 100개의 업데이트 요청 전송 결과

1. update

 

2 . createQuearyBuilder

 

3. query 작성

 

4. save

 

업데이트 방식 평균 처리 속도 (ms)
query 작성방식 7 ms
save 메소드 42.7ms
createQueryBuilder 메소드 68 ms
update 메소드 80 ms

 

1등 : query 작성방식

하지만 이 방식은 MySQL 과 같은 방식의 문법을 제공하는 데이터베이스에서만 사용이 가능하다는 단점이 존재한다.

 

2등: save 메소드

save 메소드는 주어진 데이터에 id 가 있으면 기존의 데이터 베이스 해당 데이터가 있는지 확인하고 있으면 업데이트를 한다.

주어진 데이터에 있는 id 가 데이터 베이스에 없으면 새로운 엔티티로 간주하고 데이터를 저장한다.

  - 데이터베이스가 자동으로 ID를 생성하도록 설정된 경우 : 주어진 id 를 무시하고 데이터베이스가 새로운 id 를 생성한다.

   

3등 : createQueryBuilder

for 문을 이용했지만, 이 방식을 이용하면 조인, 복잡한 조건, 서브쿼리 등을 활용할 수 있어서 유용해 보인다.

 

4등 : update 메소드

createQueryBuilder 와 같은 복잡한 쿼리 구성을 제공하지않아 간단한 업데이트를 할때 활용하면 좋을 것 같다.

 

 

 

결론

범용성을 고려하여 TypeORM 에서 제공해주는 메소드 save 를 이용하는 것이 좋아 보인다.

복잡한 방식의 조건 처리라면 createQueryBuilder  를 이용하는 방식이 더 좋아 보인다.

 

 

 

실험 환경

TypeORM, MySQL, Nest.js, TypeScript 이용

 

코드

// Insert
async bulkInsert(users: User[]) {
    const newUser = users.map((user: User) => new User({ name: user.name }));
    const startTime = Date.now();
    const insertResult = await this.userRepository.insert(newUser);
    const result = insertResult.identifiers.map((user: User) => {
      return { id: user.id };
    });
    const duration = Date.now() - startTime;
    this.logger.log(
      `Bulk "insert" of ${users.length} users completed in ${duration}ms`,
    );
    return { duration, result: result.length };
  }
  
// Save
async bulkSave(users: User[]) {
    const newUser = users.map((user: User) => new User({ name: user.name }));
    const startTime = Date.now();
    const result = await this.userRepository.save(newUser);
    const duration = Date.now() - startTime;
    this.logger.log(
      `Bulk "save" of ${users.length} users completed in ${duration}ms`,
    );
    return { duration, result: result.length };
  }

 

Postman 을 이용하여 실험

4 명의 유저

Insert 방식을 이용한 결과
save 를 이용한 결과

100 명을 저장해본 결과

 

300 명을 저장해본 결과

  insert save
4 명 3 ms (평균)  8 ms (평균)
100명 12 ms 43 ms
300명 28 ms 91 ms

 

결론

ms 단위의 차이라 미세하지만 데이터가 늘어나면 늘어날수록 insert가 더 빠르게 처리하는 것을 알 수 있다.

 

+ Recent posts