← 홈페이지 5강 목록으로
🪶
EPISODE 04
better-sqlite3 · prepare/run/get/all · CRUD API · schema.prisma · migrate · Client · 1:N 관계 · Atlas · Mongoose · Schema/Model · CRUD

Node.js + SQLite · Prisma ORM · MongoDB 기초

Node.js에서 SQLite를 다루는 가장 인기 있는 better-sqlite3 라이브러리로 prepare/run/get/all 메서드를 익히고, Express와 결합한 CRUD API를 만듭니다. 차세대 ORM Prisma로 schema.prisma 파일에 모델을 정의하고, 마이그레이션으로 DB 스키마를 관리하며, 자동 생성된 Client로 타입 안전한 CRUD를 작성합니다. NoSQL의 대표 MongoDB의 문서·컬렉션 개념, Atlas 무료 클러스터 생성, Mongoose로 Node에서 연결, Schema/Model 정의와 CRUD를 익힙니다.

better-sqlite3CRUDAPIPrismaORMmigrationMongoDBMongooseNoSQLAtlas
소요 시간
⏱ 45~60분 + 60분 + 60분
난이도
📊 중급
선수 조건
🎯 db-03
결과물
Express + SQLite로 동작하는 책 목록 CRUD API / User-Post 1:N 관계가 있는 SQLite 기반 앱 / Atlas에 연결된 메모 CRUD API

이 강의에서 배우는 것

  • 1better-sqlite3를 설치하고 DB를 연다
  • 2prepare로 쿼리를 컴파일한다
  • 3run/get/all 메서드를 적절히 사용한다
  • 4위치/이름 파라미터 바인딩으로 SQL 인젝션을 방지한다
  • 5ORM의 개념과 장단점을 이해한다
  • 6Prisma의 동작 흐름(schema → migrate → Client)을 안다
  • 7schema.prisma의 모델/필드/속성을 작성한다
  • 8prisma migrate dev로 마이그레이션을 적용한다
  • 9Prisma Client의 create/findMany/update/delete를 사용한다
  • 10include로 관계 데이터를 함께 조회한다
  • 11Database/Collection/Document/Field 개념을 안다
  • 12MongoDB Atlas 무료 클러스터를 생성하고 접속 URL을 얻는다
  • 13Mongoose로 연결, Schema/Model을 정의한다
  • 14create/find/findById/findByIdAndUpdate/findByIdAndDelete를 사용한다
  • 15MongoDB와 RDB 중 적합한 상황을 판단한다

Node.js + SQLite

Node.js에서 SQLite를 다루는 가장 인기 있는 better-sqlite3 라이브러리로 prepare/run/get/all 메서드를 익히고, Express와 결합한 CRUD API를 만듭니다.

1. better-sqlite3 소개

  • 동기식(Synchronous) API — async/await 불필요
  • 빠른 성능
  • Prepared Statement로 SQL 인젝션 방지
  • TypeScript 타입 정의 내장
bash
npm install better-sqlite3
npm install express

2. 기본 사용법

javascript
const Database = require('better-sqlite3');
const db = new Database('library.db');  // 없으면 자동 생성

3. prepare / run / get / all

prepare — SQL 준비

javascript
const stmt = db.prepare('SELECT * FROM books WHERE id = ?');

run — INSERT/UPDATE/DELETE

javascript
const insert = db.prepare('INSERT INTO books (title, author) VALUES (?, ?)');
const result = insert.run('클린 코드', '로버트 마틴');

console.log(result.lastInsertRowid);  // 삽입된 행의 ID
console.log(result.changes);          // 영향받은 행 수

get — 단일 행

javascript
const book = db.prepare('SELECT * FROM books WHERE id = ?').get(1);
// { id: 1, title: '클린 코드', author: '로버트 마틴' } | undefined

all — 여러 행

javascript
const books = db.prepare('SELECT * FROM books WHERE category = ?').all('프로그래밍');
// 배열 (없으면 빈 배열)

4. 메서드 비교

메서드용도반환값
run()INSERT/UPDATE/DELETE{ lastInsertRowid, changes }
get()SELECT 단일객체 또는 undefined
all()SELECT 여러배열 (빈 배열 가능)

5. 파라미터 바인딩

javascript
// 위치 (?)
db.prepare('SELECT * FROM books WHERE price > ? AND category = ?').all(20000, '프로그래밍');

// 이름 (@)
db.prepare('SELECT * FROM books WHERE price > @minPrice AND category = @cat')
  .all({ minPrice: 20000, cat: '프로그래밍' });

절대 문자열 결합으로 쿼리 만들지 마세요. SQL 인젝션 위험.

6. 테이블 초기화

javascript
db.exec(`
    CREATE TABLE IF NOT EXISTS books (
        id      INTEGER PRIMARY KEY AUTOINCREMENT,
        title   TEXT    NOT NULL,
        author  TEXT    NOT NULL,
        price   INTEGER DEFAULT 0
    )
`);

7. ORM의 개념

SQL 방식

javascript
const book = db.prepare('SELECT * FROM books WHERE id = ?').get(1);

ORM 방식 (Prisma)

javascript
const book = await prisma.book.findUnique({ where: { id: 1 } });
  • 장점: SQL 직접 안 써도 됨, 타입 안전, 마이그레이션 도구
  • 단점: 복잡한 쿼리는 표현 어려움, 추가 학습 비용

Prisma ORM

차세대 ORM Prisma로 schema.prisma 파일에 모델을 정의하고, 마이그레이션으로 DB 스키마를 관리하며, 자동 생성된 Client로 타입 안전한 CRUD를 작성합니다.

1. Prisma란

text
schema.prisma (모델 정의)
    ↓ npx prisma migrate dev
DB 테이블 자동 생성
    ↓
Prisma Client (자동 생성 코드)
    ↓
JavaScript 코드에서 타입 안전한 DB 조작
javascript
// 기존 (better-sqlite3)
const users = db.prepare('SELECT * FROM users WHERE age > ?').all(20);

// Prisma
const users = await prisma.user.findMany({
  where: { age: { gt: 20 } }
});

2. 설치 및 초기화

bash
npm init -y
npm install @prisma/client
npm install -D prisma

npx prisma init --datasource-provider sqlite
text
prisma/
└── schema.prisma   ← 모델 정의
.env                ← DATABASE_URL

3. schema.prisma

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

datasource db {
    provider = "sqlite"
    url      = env("DATABASE_URL")
}

model User {
    id        Int      @id @default(autoincrement())
    email     String   @unique
    name      String
    posts     Post[]
    createdAt DateTime @default(now())
}

model Post {
    id        Int      @id @default(autoincrement())
    title     String
    content   String
    published Boolean  @default(false)
    author    User     @relation(fields: [authorId], references: [id])
    authorId  Int
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
속성설명
@id기본키
@default(autoincrement())자동 증가
@unique유니크
@default(now())현재 시각
@updatedAt수정 시 자동 갱신
@relation관계 정의

4. 마이그레이션

bash
npx prisma migrate dev --name init   # 생성·적용
npx prisma migrate status            # 목록
npx prisma studio                    # GUI 도구

5. Prisma Client CRUD

javascript
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();

// Create
const user = await prisma.user.create({
  data: { email: 'kim@example.com', name: '김철수' }
});

// Read - many
const users = await prisma.user.findMany();

// Read - 조건/정렬/제한
const active = await prisma.user.findMany({
  where: { posts: { some: { published: true } } },
  orderBy: { createdAt: 'desc' },
  take: 10,
});

// Read - 단일
const user = await prisma.user.findUnique({ where: { id: 1 } });

// Update
await prisma.user.update({
  where: { id: 1 },
  data: { name: '김영수' }
});

// Delete
await prisma.user.delete({ where: { id: 1 } });

6. 관계 데이터

javascript
// include로 관련 데이터 함께 조회
const userWithPosts = await prisma.user.findUnique({
  where: { id: 1 },
  include: { posts: true }
});

// 기존 유저와 연결
const post = await prisma.post.create({
  data: {
    title: '첫 번째 포스트',
    content: '내용',
    author: { connect: { id: 1 } }
  }
});

// 중첩 create
const userWithPost = await prisma.user.create({
  data: {
    name: '이영희',
    email: 'lee@example.com',
    posts: { create: [{ title: '포스트 1', content: '내용 1' }] }
  }
});

MongoDB 기초

NoSQL의 대표 MongoDB의 문서·컬렉션 개념, Atlas 무료 클러스터 생성, Mongoose로 Node에서 연결, Schema/Model 정의와 CRUD를 익힙니다.

1. NoSQL — 문서/컬렉션

SQLMongoDB설명
데이터베이스Database같음
테이블Collection문서의 묶음
행(Row)Document하나의 데이터
열(Column)Field데이터의 속성
기본키(PK)_id자동 ObjectId
json
{
  "_id": "64a7c8e3f9b12345678abcde",
  "title": "오늘 할 일",
  "content": "MongoDB 공부하기",
  "tags": ["공부", "개발"],
  "author": { "name": "김철수", "email": "kim@example.com" },
  "createdAt": "2024-03-15T10:00:00.000Z"
}

관련 데이터를 문서 안에 중첩(embed) 가능 → JOIN 없이 하나의 쿼리로 조회.

2. MongoDB Atlas 무료 클러스터

  1. https://www.mongodb.com/atlas 접속 → 회원가입
  2. Build a Database → Free (M0) 선택
  3. AWS / Seoul (ap-northeast-2)
  4. Create
  5. Database Access — 사용자 추가 (비밀번호 기록!)
  6. Network Access — Allow Access from Anywhere
  7. Connect → Connection String 복사
text
mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/myDB?retryWrites=true&w=majority

3. Mongoose 연결

bash
npm install mongoose express dotenv
text
# .env
MONGODB_URI=mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/myDB
javascript
const mongoose = require('mongoose');

mongoose.connect(process.env.MONGODB_URI)
    .then(() => console.log('MongoDB 연결 성공'))
    .catch((err) => console.error('연결 실패:', err));

4. Schema / Model

javascript
const mongoose = require('mongoose');

const memoSchema = new mongoose.Schema(
    {
        title:    { type: String, required: true },
        content:  { type: String, required: true },
        tags:     [String],
        isPublic: { type: Boolean, default: false },
    },
    { timestamps: true }   // createdAt, updatedAt 자동
);

// 컬렉션명은 자동으로 소문자 복수형 (Memo → memos)
const Memo = mongoose.model('Memo', memoSchema);
module.exports = Memo;

5. CRUD

Create

javascript
// new + save
const memo = new Memo({ title: '제목', content: '내용', tags: ['공부'] });
await memo.save();

// create (권장)
const memo = await Memo.create({ title: '제목', content: '내용' });

Read

javascript
const memos = await Memo.find();
const memos = await Memo.find({ tags: '공부' });
const memos = await Memo.find().sort({ createdAt: -1 }).limit(10);
const memo = await Memo.findById('64a7c8e3f9b12345678abcde');
const memo = await Memo.findOne({ title: '오늘 할 일' });

Update

javascript
const updated = await Memo.findByIdAndUpdate(
    id,
    { title: '새 제목' },
    { new: true }   // 수정 후 문서 반환
);

Delete

javascript
await Memo.findByIdAndDelete(id);

6. 언제 MongoDB?

MongoDB 유리

  • 데이터 구조가 자주 바뀌는 프로젝트
  • 문서 안에 배열/중첩 객체가 많은 경우 (태그, 댓글 배열)
  • 대용량 비정형 데이터 (로그, 이벤트)
  • 빠른 수평 확장이 필요한 경우

RDB 유리

  • 데이터 간 복잡한 관계가 많은 경우
  • 금융/결제 등 트랜잭션 무결성 중요
  • 정해진 스키마로 데이터 일관성 중요
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 주세요.

댓글은 회원만 쓸 수 있습니다.

광고·욕설·비방·개인정보·불법 내용이 담긴 댓글은 숨기거나 지웁니다. 댓글은 닉네임과 함께 공개됩니다. 개인정보처리방침