개요

findUnique로 단일 레코드 조회하면서 관련된 데이터까지 한 번에 가져오고 싶을 때 whereinclude를 어떻게 조합해야 하는지 정리함 관계 필터링을 where에 넣을 수 있는지, include에서 필터가 가능한지 헷갈리기 쉬운 지점 정리

핵심 개념

  • findUnique는 유니크 키로 정확히 하나의 레코드를 찾는 용도
  • findUniquewhere유니크 필드만 허용됨, 관계 필터나 일반 조건 결합 불가
  • include는 조회된 레코드에 대한 연관 레코드를 함께 가져오는 옵션
  • to-many 관계에 한해 include 내부에서 where 사용 가능, to-one 관계는 where 불가

where 사용 패턴

  • 잘못된 예시
// findUnique에 관계 필터 결합 시도 → 타입 에러
// (User(1) → Post(N) → Metadata(1) 관계)
await db.user.findUnique({
  where: {
    id: userId,
    // 'posts'는 유니크 필드가 아니므로 'where'에서 관계 필터링 불가
    posts: { some: { metadata: { editorEmail: email } } },
  },
});
  • 올바른 최소 조건
await db.user.findUnique({
  where: { id: userId }, // 'id'는 유니크 필드
});
  • 관계 조건이 필요하면 findFirst 또는 findMany 사용
// 'findUnique'가 아닌 'findFirst'를 사용하면
// 'where'에 관계 필터를 포함할 수 있음
await db.user.findFirst({
  where: {
    id: userId,
    posts: { some: { metadata: { editorEmail: email } } },
  },
});

요약하면 findUnique에는 유니크 조건만, 관계 기반 필터는 findFirst 또는 findMany로 처리함

include 사용 패턴

  • 올바른 기본 형태 (User → Posts → Metadata 관계)
await db.user.findUnique({
  where: { id: userId },
  include: {
    posts: { include: { metadata: true } }, // 'posts'와 중첩된 'metadata' 포함
  },
});
  • 잘못된 형태
// include에 관계 필터를 직접 넣는 구문은 불가
include: {
  posts: {
    // 'include' 내부에서 필터링을 이렇게 할 수 없음 (Prisma 4.x 이하)
    // 'include'는 'true' 또는 다른 include/select 객체만 받음
    include: { metadata: { editorEmail: email } },
  },
}
  • 의도에 부합하는 형태 (Prisma 5.x+ 권장)
await db.user.findUnique({
  where: { id: userId },
  include: {
    posts: {
      // to-many 관계인 'posts'에 'where'를 걸어 필터링
      where: { metadata: { editorEmail: email } },
      // 필터링된 'posts'에 연결된 'metadata'를 포함
      include: { metadata: true },
    },
  },
});

설명

  • to-many 관계인 postswhere를 걸어 하위 metadataeditorEmail로 필터링 가능
  • 조건에 맞지 않는 posts는 제외되어 빈 배열([])로 반환됨
  • to-one 관계는 include에서 where를 쓸 수 없으며, 관계가 없으면 해당 필드는 null 반환

결론 예시

단일 User를 유니크 키로 찾고, 연관된 Posts는 특정 email을 가진 Metadata가 있는 경우만 포함하고, 사용자의 ProfileRole도 함께 가져오고 싶다면 아래 형태를 권장

const userId = "user-unique-id-123";
const email = "target-editor@example.com";

await db.user.findUnique({
  where: { id: userId },
  include: {
    // 1. (to-many) 'posts' 관계
    posts: {
      // 2. 'posts' 목록을 'metadata.editorEmail' 기준으로 필터링
      where: { metadata: { editorEmail: email } },
      // 3. 필터링을 통과한 'posts'의 'metadata'도 함께 로드
      include: { metadata: true },
    },
    // 4. (to-one) 'profile' 관계
    profile: true,
    // 5. (to-one) 'role' 관계
    role: true,
  },
});

주의 사항

  • findUniquewhere에는 유니크 필드만 입력 가능, 관계 필터 결합 불가
  • 관계 조건이 결합된 조회가 필요하면 findFirst 또는 findMany로 상위 where에 관계 필터 사용
  • includewhereto-many 관계에만 적용 가능
  • to-many 관계에서 includewhere 조건 미매칭 시, 해당 관계는 null이 아닌 빈 배열([]) 반환
  • 선택적 필드 제어가 필요하면 selectinclude를 목적에 맞게 혼용 권장

참고자료