개요
findUnique로 단일 레코드 조회하면서 관련된 데이터까지 한 번에 가져오고 싶을 때 where와 include를 어떻게 조합해야 하는지 정리함
관계 필터링을 where에 넣을 수 있는지, include에서 필터가 가능한지 헷갈리기 쉬운 지점 정리
핵심 개념
findUnique는 유니크 키로 정확히 하나의 레코드를 찾는 용도findUnique의where는 유니크 필드만 허용됨, 관계 필터나 일반 조건 결합 불가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 관계인
posts에where를 걸어 하위metadata의editorEmail로 필터링 가능 - 조건에 맞지 않는
posts는 제외되어 빈 배열([])로 반환됨 - to-one 관계는
include에서where를 쓸 수 없으며, 관계가 없으면 해당 필드는null반환
결론 예시
단일 User를 유니크 키로 찾고, 연관된 Posts는 특정 email을 가진 Metadata가 있는 경우만 포함하고, 사용자의 Profile과 Role도 함께 가져오고 싶다면 아래 형태를 권장
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,
},
});
주의 사항
findUnique의where에는 유니크 필드만 입력 가능, 관계 필터 결합 불가- 관계 조건이 결합된 조회가 필요하면
findFirst또는findMany로 상위where에 관계 필터 사용 include의where는 to-many 관계에만 적용 가능- to-many 관계에서
include의where조건 미매칭 시, 해당 관계는null이 아닌 빈 배열([]) 반환 - 선택적 필드 제어가 필요하면
select와include를 목적에 맞게 혼용 권장