CRUD[Prisma]

SnowCat·2023년 5월 16일
0

Prisma

목록 보기
3/10
post-thumbnail
post-custom-banner
  • 다음의 스키마가 이미 작성되었다는 가정하에 아래 문서가 진행된다.
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model ExtendedProfile {
  id        Int    @id @default(autoincrement())
  biography String
  user      User   @relation(fields: [userId], references: [id])
  userId    Int    @unique
}

model User {
  id           Int              @id @default(autoincrement())
  name         String?
  email        String           @unique
  profileViews Int              @default(0)
  role         Role             @default(USER)
  coinflips    Boolean[]
  posts        Post[]
  profile      ExtendedProfile?
}

model Post {
  id         Int        @id @default(autoincrement())
  title      String
  published  Boolean    @default(true)
  author     User       @relation(fields: [authorId], references: [id])
  authorId   Int
  comments   Json?
  views      Int        @default(0)
  likes      Int        @default(0)
  categories Category[]
}

model Category {
  id    Int    @id @default(autoincrement())
  name  String @unique
  posts Post[]
}

enum Role {
  USER
  ADMIN
}

Create

단일 레코드 생성

  • prisma에 정의된 스키마에 맞게 prisma.model.create를 사용해 레코드를 생성함
const user = await prisma.user.create({
  data: {
    email: 'elsa@prisma.io',
    name: 'Elsa Prisma',
  },
})

/*
{
  id: 22,
  name: 'Elsa Prisma',
  email: 'elsa@prisma.io',
  profileViews: 0,
  role: 'USER',
  coinflips: []
}
*/
  • 객체를 전달하기만 하면 되기 때문에 상황에 따라 분기 처리를 해줄수도 있음
const includePosts = someCheckFunction();
if (includePosts) {
  user = {
    email: 'elsa@prisma.io',
    name: 'Elsa Prisma',
    posts: {
      create: {
        title: 'Include this post!',
      },
    },
  }
} else {
  user = {
    email: 'elsa@prisma.io',
    name: 'Elsa Prisma',
  }
}

여러개의 레코드 생성

  • prisma.model.createMany를 사용해 모델의 객체 배열을 전달해주면 됨
    내부적으로는 INSERT INTO문을 통해 작동함
const createMany = await prisma.user.createMany({
  data: [
    { name: 'Bob', email: 'bob@prisma.io' },
    { name: 'Bobo', email: 'bob@prisma.io' }, // unique key 중복
    { name: 'Yewande', email: 'yewande@prisma.io' },
    { name: 'Angelique', email: 'angelique@prisma.io' },
  ],
  skipDuplicates: true, // 중복된 키가 있는경우 스킵을해주는 옵션
})

Read

단일 레코드 읽기

  • prisma.model.findUnique에 unique key나 id를 전달해 사용
// By unique identifier
const user = await prisma.user.findUnique({
  where: {
    email: 'elsa@prisma.io',
  },
})

// By ID
const user = await prisma.user.findUnique({
  where: {
    id: 99,
  },
})
  • 만약 compound ID를 사용하는 경우, 아래와 같이 쿼리를 작성
/*
model TimePeriod {
  year    Int
  quarter Int
  total   Decimal

  @@id([year, quarter])
}
*/

const timePeriod = await prisma.timePeriod.findUnique({
  where: {
    year_quarter: { //항목1_항목2 형식으로 이름 작성, 이름이 있을경우 이름 입력
      quarter: 4,
      year: 2020,
    },
  },
})

모든 레코드 가져오기

  • findMany 메서드를 사용해 모든 모델의 레코드를 가져올 수 있음
const users = await prisma.user.findMany()

조건에 맞는 첫번째 레코드 가져오기

  • findFirst 메서드를 사용하면 조건에 만족하는 가장 첫번째 레코드를 가져올 수 있음
// 게시글 리스트 중에 하나라도 100개이상의 좋아요를 받은 게시글 리스트 중 가장 나중에 생성된 posts 반환
  const findUser = await prisma.user.findFirst({
    where: {
      posts: {
        some: {
          likes: {
            gt: 100
          }
        }
      }
    },
    orderBy: {
      id: "desc"
    }
  })
}

조건에 맞는 여러개의 레코드 가져오기

  • findMany 메서드를 사용해 조건에 만족하는 여러개의 레코드를 가져올 수 있음
const users = await prisma.user.findMany({
  where: {
    email: {
      endsWith: 'prisma.io',
    },
  },
})

// 여러개의 쿼리를 중첩할 때에는 때에는 OR, AND 조건 사용
const users = await prisma.user.findMany({
  where: {
    OR: [
      {
        name: {
          startsWith: 'E',
        },
      },
      {
        AND: {
          profileViews: {
            gt: 0,
          },
          role: {
            equals: 'ADMIN',
          },
        },
      },
    ],
  },
})

필드의 일부 값만을 가져오기

  • where절 밑에 select 옵션을 사용해 가져올 필드를 선택할 수 있음
const user = await prisma.user.findUnique({
  where: {
    email: 'emma@prisma.io',
  },
  select: {
    email: true,
    name: true,
  },
})

/*
{ email: 'emma@prisma.io', name: "Emma" }
*/

// 하위 요소에 특정 필드만을 가져오는 경우 select를 중첩된 위치에 사용
const user = await prisma.user.findUnique({
  where: {
    email: 'emma@prisma.io',
  },
  select: {
    email: true,
    posts: {
      select: {
        likes: true,
      },
    },
  },
})

/*
{ email: 'emma@prisma.io', posts: [ { likes: 0 }, { likes: 0 } ] }
*/

다른 모델의 데이터를 함께 가져오기

  • 다른 모델의 값, 즉 JOIN이 필요한 경우 include 옵션을 사용
const users = await prisma.user.findMany({
  where: {
    role: 'ADMIN',
  },
  include: {
    posts: true,
  },
})

/*
{
    "id": 38,
    "name": "Maria",
    "email": "maria@prisma.io",
    "profileViews": 20,
    "role": "ADMIN",
    "coinflips": [
        true,
        false,
        false
    ],
    "posts": []
},
{
    "id": 39,
    "name": "Oni",
    "email": "oni2@prisma.io",
    "profileViews": 20,
    "role": "ADMIN",
    "coinflips": [
        true,
        false,
        false
    ],
    "posts": [
        {
        "id": 25,
        "authorId": 39,
        "title": "My awesome post",
        "published": true,
        "comments": null,
        "views": 0,
        "likes": 0
        }
    ]
}
*/

Update

단일 레코드 업데이트

  • prisma.model.update 메서드 사용
const updateUser = await prisma.user.update({
  where: {
    email: 'viola@prisma.io',
  },
  data: {
    name: 'Viola the Magnificent',
  },
})

여러 레코드 업데이트

  • prisma.model.updateMany 메서드 사용
const updateUsers = await prisma.user.updateMany({
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
  data: {
    role: 'ADMIN',
  },
})

레코드 존재여부가 확실하지 않을 때

  • prisma.model.upsert 메서드를 사용하면 조건을 만족하는 레코드가 있으면 값을 업데이트하고, 그렇지 않으면 새로운 레코드를 생성해줌
const upsertUser = await prisma.user.upsert({
  where: {
    email: 'viola@prisma.io',
  },
  update: {
    name: 'Viola the Magnificent',
  },
  create: {
    email: 'viola@prisma.io',
    name: 'Viola the Magnificent',
  },
})

숫자의 증감 업데이트

  • 각 항목에 increment를 사용하면 숫자를 증감시킬 수 있음
const updatePosts = await prisma.post.updateMany({
  data: {
    views: {
      increment: 1,
    },
    likes: {
      increment: 1,
    },
  },
})

Delete

단일 레코드 삭제

  • prisma.model.delete 메서드 사용
const deleteUser = await prisma.user.delete({
  where: {
    email: 'bert@prisma.io',
  },
})

여러 레코드 삭제

  • prisma.model.deleteMany 메서드 사용
const deleteUsers = await prisma.user.deleteMany({
  where: {
    email: {
      contains: 'prisma.io',
    },
  },
})

모든 레코드 삭제

  • deleteMany에 where 옵션을 사용하지 않으면 모든 값이 삭제됨
const deleteUsers = await prisma.user.deleteMany({})

여러 테이블에 걸쳐있는 데이터 삭제

  • 다음의 쿼리를 실행시키면 오류가 발생한다
const deleteUser = await prisma.user.delete({
  where: {
    email: 'bert@prisma.io',
  },
}) // The change you are trying to make would violate the required relation 'PostToUser' between the `Post` and `User` models.
  • 즉 현재 상황에서는 post가 있는 user를 삭제하지 못한다.
  • 문제를 해결하기 위해서는 relation을 optional로 설정해주어야 한다.
model Post {
  id       Int   @id @default(autoincrement())
  author   User? @relation(fields: [authorId], references: [id])
  authorId Int?
  author   User  @relation(fields: [authorId], references: [id])
  authorId Int
}
  • 그 다음 relation이 있는 author를 다른 유저로 임시로 바꿔놓은 다음에, 트랜잭션을 이용해 데이터를 삭제해준다.
const deletePosts = prisma.post.deleteMany({
  where: {
    authorId: 7,
  },
})

const deleteUser = prisma.user.delete({
  where: {
    id: 7,
  },
})

const transaction = await prisma.$transaction([deletePosts, deleteUser])

출처:
https://www.prisma.io/docs/concepts/components/prisma-client/crud

profile
냐아아아아아아아아앙
post-custom-banner

0개의 댓글