Prisma findUnique에서 where와 include 제대로 쓰기

개요 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로 처리함 ...

November 12, 2025

Node.js 실행 흐름과 이벤트 루프 단계 정리

개요 Node.js가 스크립트를 실행할 때 어떤 구성요소가 어떤 순서로 초기화되고 동작하는지 정리 바이너리 기동부터 모듈 로딩, V8 파싱과 실행, 이벤트 루프와 비동기 작업 처리까지의 전체 흐름을 개발자 관점에서 간결하게 설명 핵심 개념 V8 엔진, Ignition 바이트코드와 JIT 최적화 libuv, 비동기 I O 백엔드와 이벤트 루프 단계 모듈 시스템, CommonJS와 ES Module의 로딩 차이 전역 실행 컨텍스트와 런타임 내장 객체 마이크로태스크 큐와 process.nextTick의 우선순위 실행 순서 요약 Node 바이너리 시작 런타임 초기화와 내부 바인딩 준비 모듈 로더 기동 및 엔트리 파일 로드 V8 파싱과 바이트코드 컴파일 전역 실행 컨텍스트 구성과 최상위 코드 실행 비동기 작업 등록 이벤트 루프 진입 비동기 콜백 처리 반복 graph TD A[Node 시작] --> B[V8, libuv 초기화] B --> C[모듈 로딩] C --> D[파싱 및 컴파일] D --> E[최상위 코드 실행] E --> F[이벤트 루프] F --> G[비동기 처리 반복]단계별 동작 1단계 Node 바이너리 시작 node yourfile.js 실행으로 C++ 엔트리 포인트가 기동됨 V8, libuv, 내부 바인딩 계층이 초기화되고 런타임 전역 상태가 준비됨 ...

November 11, 2025

DI가 결합도를 낮추는 원리와 최소 예시

개념/배경 DI(Dependency Injection, 의존성 주입)의 핵심 아이디어는 명확함 객체가 자신이 사용할 의존 객체를 스스로 생성하지 않고, 외부로부터 전달받아 사용하는 것임 이 단순한 설계 변경만으로도 코드의 변경 용이성, 테스트 편의성, 그리고 전체 시스템의 확장성에서 거대한 차이가 발생함 문제 상황: 강한 결합 (Tight Coupling) 전형적인 문제 패턴은 클래스 내부에서 다른 구체적인 클래스(Concrete Class)를 new 키워드로 직접 생성하여 사용하는 것임 의존 대상의 구현이 변경되면, 해당 객체를 사용하는 클래스 내부 코드도 반드시 함께 수정해야 함 단위 테스트(Unit Test)를 작성할 때, 테스트 대상 객체가 의존하는 실제 객체들까지 모두 함께 엮여 들어와 테스트가 복잡하고 무거워짐 예를 들어 Gamer가 BlueSwitchKeyboard를 직접 생성해 사용한다면, Gamer는 BlueSwitchKeyboard라는 구체적인 구현에 영구적으로 고정됨 만약 키보드 종류를 RedSwitchSilentKeyboard로 바꾸려면 Gamer 클래스의 내부 코드를 직접 수정해야 함 이 상태를 결합도가 높다고 부름 ...

November 9, 2025

KISS 원리: 소프트웨어 설계에서 불필요한 복잡성 줄이기

개요 KISS는 Keep It Simple, Stupid 또는 Keep It Simple and Straightforward의 약자이며 1960년대 미 해군에서 출발한 설계 원칙입니다. 소프트웨어에서는 불필요한 복잡성을 제거하고 이해와 변경이 쉬운 구조를 지향합니다. 목표는 적은 개념과 짧은 경로로 같은 가치를 제공하는 시스템을 만드는 것임 핵심 개념 단순함 추구: 필요 최소의 개념, 규칙, 구성 요소 유지 이해 용이성: 읽고 추론하기 쉬운 흐름과 명명 유지보수 용이성: 응집도 높이고 결합도 낮춰 변경 영향 최소화 적용 방법 처음부터 모든 시나리오를 포괄하려 하지 말고 현재 요구에 맞춘 최소 기능으로 시작 큰 만능 모듈 대신 작고 역할이 분리된 구성으로 나누기 공개 인터페이스를 최소화하고 기본값을 합리적으로 설계 데이터 흐름을 단방향으로 단순화하고 예외 경로는 명시적으로 처리 관련 원칙 DRY: 중복 제거로 변경 비용과 오류 가능성 감소 YAGNI: 지금 필요 없는 기능은 만들지 않음 간단 예시 모든 옵션을 받는 doSomething(config) 하나로 처리하려는 유혹을 경계. 대신 doSimpleA, doSimpleB처럼 명확한 역할의 작은 함수로 분리하고 기본 동작을 안전하게 설계함. 설정이 꼭 필요할 때만 제한된 형태로 노출 ...

November 3, 2025

TypeScript Parameters 유틸리티 타입 개념과 안전한 활용

개념/배경 Parameters는 TypeScript가 제공하는 제네릭 유틸리티 타입으로, 특정 함수 타입의 매개변수 타입들을 튜플로 추출하는 데 사용됨 함수 래핑, 고차 함수, 어댑터 계층에서 기존 함수 시그니처를 재사용해 타입 안정성을 유지하고 중복 선언을 줄이는 목적에 적합함 문법 type Parameters<T extends (...args: any) => any> = T extends ( ...args: infer P ) => any ? P : never; T가 함수 타입이면 매개변수 목록을 튜플 타입 P로 추출 T가 함수 타입이 아니면 never 반환 추출 결과는 튜플이므로 인덱스 접근, 스프레드, 부분 적용 등 튜플 연산과 조합 가능 사용 예시 기본 추출 ...

November 1, 2025

MySQL InnoDB 버퍼 풀 개념과 동작 원리, 크기 설정 가이드

개요 InnoDB 버퍼 풀은 데이터와 인덱스 페이지를 메모리에 캐싱하는 영역임 디스크 I/O를 획기적으로 줄여 지연 시간을 낮추는 게 목적임 InnoDB 스토리지 엔진(트랜잭션, MVCC, 행 단위 락 지원) 성능의 심장부라 할 수 있음 쉽게 말해, 자주 쓰는 데이터와 인덱스를 디스크 대신 메모리에 올려두고 처리하는 구조임 버퍼 풀 구성 요소 버퍼 풀에는 주로 이런 페이지(기본 16KB)가 올라옴 데이터 페이지: 실제 테이블 로우(Row)가 저장된 페이지 인덱스 페이지: B-Tree 인덱스 노드 페이지 (PK 및 세컨더리 인덱스 포함) 기타 관리 페이지: UNDO 페이지, 트랜잭션/MVCC 관리에 필요한 메타데이터 등 핵심 개념 페이지 캐싱 InnoDB는 디스크 데이터를 페이지 단위로 다룸 클라이언트가 특정 로우를 읽고 싶어 하면, 그 로우가 속한 페이지 전체를 버퍼 풀로 가져옴 이후 같은 페이지에 있는 다른 로우를 읽을 때는 디스크를 다시 보지 않고 버퍼 풀(메모리)에서 바로 조회함 ...

October 31, 2025

NestJS Swagger 가이드 — ApiProperty와 PickType/OmitType/PartialType 사용법

개요 @nestjs/swagger는 NestJS와 Swagger(OpenAPI) 스펙을 연결해 API 문서를 자동 생성하는 모듈임 DTO(Data Transfer Object) 클래스에 메타데이터를 부여해 타입과 예시, 설명 등을 Swagger UI에 노출하는 흐름으로 작동함 핵심 도구는 @ApiProperty와 DTO 유틸리티 타입들(PickType, OmitType, PartialType)임 ApiProperty 개념과 사용 @ApiProperty는 DTO 속성 단위로 문서화 메타데이터를 부여하는 데코레이터임 타입, 설명, 예시, 필수 여부 등을 정의해 Swagger UI에 명확한 스키마 제공 코드와 문서가 한 소스에서 유지되어 일관성 확보에 유리함 간단 사용 예시 class CreateUserDto { @ApiProperty({ description: "사용자 이름", example: "John Doe" }) name: string; }이 속성 정의만으로 Swagger 스키마에 name 필드의 설명과 예시가 노출됨 ...

October 30, 2025

Prisma cursor 기반 페이지네이션 동작 원리와 skip: 1의 의미

개요 Prisma에서 cursor는 특정 레코드 지점부터 결과를 읽기 시작하는 기준점으로 동작함 skip: 1은 해당 cursor 레코드를 결과에서 제외하기 위한 옵션으로, 페이지 간 중복을 제거하는 데 사용함 핵심 동작 cursor는 그 지점부터 시작 await prisma.user.findMany({ cursor: { id: 100 }, take: 5, orderBy: { id: "asc" }, }); // 결과: 100부터 시작해 5개 반환 skip: 1은 cursor에 해당하는 레코드를 건너뜀 await prisma.user.findMany({ cursor: { id: 100 }, skip: 1, take: 5, orderBy: { id: "asc" }, }); // 결과: 101부터 5개 반환 예시로 보는 차이 데이터가 아래와 같다고 가정 ...

October 29, 2025

Prisma findMany 가이드: where, select/include, 정렬·페이징, in/비교 연산자

개요 Prisma의 findMany는 다중 레코드 조회용 메서드 기본값은 대상 모델의 모든 레코드 반환 where 필터, select/include, 정렬, 페이징, 중복 제거 등 옵션 지원 옵션 조합으로 조건 기반 조회를 간결하게 구성 가능 기본 사용법 가장 단순한 호출 형태 const users = await prisma.user.findMany();주요 옵션 옵션은 필요한 것만 선택적으로 사용 where: 조건 필터링 select: 필드 서브셋 선택 include: 관계 데이터 로드 orderBy: 정렬 기준 지정 skip, take: 오프셋 기반 페이징 distinct: 특정 필드 기준 중복 제거 where로 조건 필터링 단일 조건부터 복합 조건까지 표현 가능 ...

October 28, 2025

JavaScript 함수는 왜 일급 객체인가 — 의미와 활용

개요 JavaScript에서 함수는 일급 객체로 취급됨 이는 함수가 값처럼 변수에 담기고, 인수로 전달되고, 반환값으로 나오며, 객체의 프로퍼티로 저장될 수 있음을 의미함 이 특성 덕분에 고차 함수, 콜백, 클로저, 함수 합성 같은 패턴이 자연스럽게 구현됨 핵심 개념 변수에 할당 가능 다른 함수의 인수로 전달 가능 다른 함수의 반환값으로 사용 가능 객체의 프로퍼티로 저장 가능 간단 예시 변수에 할당 const greet = (name) => `Hello, ${name}`;인수로 전달 const run = (fn, v) => fn(v); run(greet, "Bob");반환값으로 사용 및 클로저 const mul = (m) => (v) => v * m; mul(2)(5);객체 프로퍼티로 저장해 메서드 구성 ...

October 27, 2025