본문 바로가기
Prisma

[Prisma] 5. Nested Queries

by spare8433 2025. 1. 17.

앞으로 등장할 코드에서 prisma 변수는 const prisma = new PrismaClient() 를 의미합니다.
mysql 사용 기준으로 작성되어 몇몇 기능 및 지원에 대한 내용이 없을 수 있습니다.




Nested Queries

단일 Prisma Client 쿼리를 사용하여 여러 테이블의 데이터를 한 번에 생성, 업데이트 또는 삭제할 수 있도록 하며, 이 모든 작업이 트랜잭션으로 처리되도록 보장합니다.



쉽게 말해, 여러 테이블 간의 관계를 처리할 때, 한 번의 요청으로 모든 관련 데이터를 안전하게 처리할 수 있습니다. 만약 작업 중 하나라도 실패하면, 전체 작업이 롤백되어 데이터의 일관성을 유지할 수 있습니다.





관련 레코드 생성

createMany()중첩된 관계를 처리하지 않고 단순히 여러 레코드를 생성할 때 사용되므로 중첩된 관계를 포함한 데이터 생성하기 위해서는 create()를 사용해 중첩 쿼리를 사용해야합니다.



create : 관계된 모델의 단일 레코드 생성

추가적으로 create, createMany 중첩 가능 (createMany 를 사용하는 경우 더 이상 중첩 하여 사용 불가능, 관계만 적절하다면 create 는 계속 중첩 가능)



const user = await prisma.user.create({
  data: {
    email: 'alice@prisma.io',
    profile: {
      create: { bio: 'Hello World' },
    },
  },
});

// 일대다 관계일 경우 배열을 전달하여 한 번에 여러 개의 레코드를 생성 가능
const user = await prisma.user.create({
  data: {
    email: 'alice@prisma.io',
    posts: {
      create: [
        { title: 'This is my first post' },
        { title: 'Here comes a second post' },
      ],
    },
  },
});

// update() 에서 create 사용 가능
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      create: { title: 'Hello World' },
    },
  },
})





createMany : 관계된 모델의 여러 레코드 생성


createMany() 일대다 관계에서 사용 가능하고 다대다 관계에서 사용 불가능합니다.


createMany 안에서는 추가적으로 createcreateMany 를 중첩해서 쿼리르 사용할 수 없지만, 따로 쿼리를 분리해 처리하는 로직을 구성하여 처리 가능


외래 키를 직접 설정할 수 있습니다.



const user = await prisma.user.update({
  where: {
    id: 9,
  },
  data: {
    name: 'Elliott',
    posts: {
      createMany: {
        data: [{ title: 'My first post' }, { title: 'My second post' }],
      },
    },
  },
});





관계 레코드 연결



connect : 기존 관계 모델의 레코드 연결

관련 레코드를 생성하거나 업데이트할 때 중첩 쿼리로 사용 가능



const result = await prisma.user.create({
  data: {
    email: 'vlad@prisma.io',
    posts: {
      connect: [{ id: 8 }, { id: 9 }, { id: 10 }],
    },
  },
})





connectOrCreate : 기존 관계모델의 레코드에 연결 만약 없을 경우 생성 후 연결



Race Condition 이 발생할 수 있으므로 생성되는 필드의 제약조건을 활용하여 중복데이터 생성을 방지 합니다.



Race Condition : 여러 쿼리가 동시에 실행되면, 데이터가 없는 상태에서 두 쿼리가 동시에 생성 작업을 시도할 수 있습니다. 이 과정에서 중복 데이터가 생성될 가능성이 있습니다.



const result = await prisma.post.create({
  data: {
    title: 'How to make croissants',
    author: {
      connectOrCreate: {
        where: { email: 'viola@prisma.io' },
        create: {
          email: 'viola@prisma.io',
          name: 'Viola',
        },
      },
    },
  },
})





disconnect : 레코드 간의 연결 끊기

관계가 선택 사항인 경우에만 사용 가능합니다.



const user = await prisma.user.update({
  where: { email: 'bob@prisma.io' },
  data: {
    profile: { disconnect: true },
  },
});





관계 레코드 변경



set : 관계된 레코드 목록을 다른 레코드 목록으로 변경



const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      set: [{ id: 32 }, { id: 42 }],
    },
  },
});





update: 관련된 레코드 업데이트

update() 쿼리 내에서만 사용 가능하며 하나 이상의 관련 레코드를 업데이트



// 단일 레코드 업데이트 (일대일 관계일 경우 where 생략)
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    profile: {
      update: { bio: 'Hello World' },
    },
  },
});

// 여러 레코드 업데이트
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      update: [
        {
          data: { published: true },
          where: { id: 32 },
        },
        {
          data: { published: true },
          where: { id: 23 },
        },
      ],
    },
  },
});





updateMany: 관련된 레코드 목록 업데이트

const result = await prisma.user.update({
  where: { id: 2 },
  data: {
    posts: {
      updateMany: {
        where: { published: false },
        data: { likes: 0 },
      },
    },
  },
});





upsert : 특정 관련 레코드가 있으면 업데이트하고, 그렇지 않으면 새로운 관련 레코드 생성

// 단일 레코드 업데이트  (일대일 관계일 경우 where 생략)
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    profile: {
      upsert: {
        create: { bio: 'Hello World' },
        update: { bio: 'Hello World' },
      },
    },
  },
});

// 여러 레코드 업데이트
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      upsert: [
        {
          create: { title: 'This is my first post' },
          update: { title: 'This is my first post' },
          where: { id: 32 },
        },
        {
          create: { title: 'This is my second post' },
          update: { title: 'This is my second post' },
          where: { id: 23 },
        },
      ],
    },
  },
});





delete : 관련된 레코드를 삭제

관계가 선택 사항인 경우에만 사용 가능합니다.

// 단일 관련 레코드 삭제
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    profile: { delete: true },
  },
});

// 여러 관련 레코드 삭제
const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      delete: [{ id: 34 }, { id: 36 }],
    },
  },
});





deleteMany :관련된 레코드 목록을 삭제

const result = await prisma.user.update({
  where: { id: 2 },
  data: {
    name: 'Updated name',
    posts: {
      deleteMany: {},
    },
  },
});






참고

https://www.prisma.io/docs/orm/reference/prisma-client-reference#nested-queries
https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries#nested-writes