Ayden's journal

Computed Field

Computed Field는 이름에서 알 수 있듯 다른 필드나 값을 기반으로 '계산된' 결과를 반환하는 필드를 말한다. 이러한 필드는 실제 데이터베이스에는 저장되지 않고, 필요할 때마다 계산하여 제공된다. 따라서 데이터의 중복 저장을 방지하고, 항상 최산의 값을 계산해 제공할 수 있다는 장점이 있다. 그러나 계산 비용이 큰 경우 성능에 영향을 줄 수 있기 때문에 주의해서 사용해야 한다.

 

유저의 이름과 이메일을 관리하는 User 모델이 있다. 서비스가 안정적으로 3년 정도 제공된 기념으로 모든 유저들에게 30% 할인 쿠폰을 제공하고자 한다. 이때, 유저의 fullName으로 이메일을 시작하고자 한다. 만약 computed field가 없었다면 user를 조회한 뒤 user.firstName과 user.lastName을 가져와 문자열을 붙여서 사용해야 했을 것이다.

model User {
  id           Int       @id @default(autoincrement())
  email        String    @unique
  firstName    String
  lastName     String
  title        Title
  createdAt    DateTime  @default(now())
  updatedAt    DateTime  @updatedAt
}

 

그러나 computed field를 사용하면 PrismaClient 수준에서 계산된 필드를 제공해준다. 아래는 computed fullName Field에 대한 예시이다.

const prisma = new PrismaClient().$extends({
  result: {
    user: {
      fullName: {
        needs: { firstName: true, lastName: true },
        compute(user) {
          return `${user.firstName} ${user.lastName}`
        },
      },
    },
  },
})

 

computed field의 장점은 re-computed field에서 드러난다. 만약 fullName도 필요하고, title이 앞에 붙은 titleFullName도 필요하다면 아래와 같이 추가 확장을 통해 기존의 computed field를 다시 계산에 사용할 수 있다.

 

const prisma = new PrismaClient()
  .$extends({
    result: {
      user: {
        fullName: {
          needs: { firstName: true, lastName: true },
          compute(user) {
            return `${user.firstName} ${user.lastName}`
          },
        },
      },
    },
  })
  .$extends({
    result: {
      user: {
        titleFullName: {
          needs: { title: true, fullName: true },
          compute(user) {
            return `${user.title} (${user.fullName})`
          },
        },
      },
    },
  })

 

computed field를 통해 우리는 DB에 fullName과 titleFullName과 같은 필드를 미리 준비해놓지 않더라도 마치 DB에 그러한 필드가 있는 것처럼 사용할 수 있다. 덕분에 DB에 불필요한 중복 데이터를 쌓아두지 않을 수 있는 것이다.

다만, 이렇게 계산된 필드들은 쿼리를 통해 자동으로 리턴되지는 않는다. 때문에 계산된 필드를 사용하고자 한다면 반드시 select로 해당 필드를 선택해주어야 한다. 그렇지 않으면 객체에 존재하지 않는 프로퍼티 값에 접근하는 행위가 되므로 undefined를 반환받게 될 것이다.

const user = await prisma.user.findUnique({
  where: { id : 1 },
})
console.log(user.fullName) // undefined


const user = await prisma.user.findUnique({
  where: { id : 1 },
  select: { fullName: true },
})
console.log(user.fullName) // "Ayden Blair"

블로그의 정보

Ayden's journal

Beard Weard Ayden

활동하기