Node.js와 MongoDB 연결 및 Mongoose CRUD 구현
Node.js와 MongoDB를 Mongoose로 연결하고 기본 CRUD를 구현하는 실습형 설명 자료. 초기 설정부터 모델 설계, CRUD 예제 및 테스트 방법까지 정리된 자료
목차
소개
이 글은 Node.js 환경에서 MongoDB를 Mongoose로 연결하고, 기본적인 CRUD(Create, Read, Update, Delete)를 구현하는 과정을 단계별로 설명한다. 처음 접하는 개발자도 이해하기 쉽도록 용어와 절차를 간결하게 정리했다.
필수 구성 요소
- Node.js (v14 이상 권장)
- MongoDB 로컬 또는 Atlas 클러스터
- npm 또는 yarn
- Express(선택) 및 Mongoose 패키지
프로젝트 초기 설정
프로젝트 폴더 생성과 패키지 초기화, 필요한 패키지 설치 과정을 간단히 소개한다. Express는 라우팅과 미들웨어 처리를 위해 사용한다.
npm init -y
npm install express mongoose
Mongoose 연결 설정
Mongoose를 통해 MongoDB에 연결할 때는 연결 문자열과 옵션을 함께 사용한다. 연결 상태 이벤트로 연결 성공과 오류를 확인할 수 있다.
const express = require('express')
const mongoose = require('mongoose')
const app = express()
app.use(express.json())
const uri = 'mongodb://localhost:27017/mydb' // 또는 Atlas 연결 문자열
mongoose.connect(uri, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const db = mongoose.connection
db.on('error', (err) => console.error('MongoDB 연결 오류:', err))
db.once('open', () => console.log('MongoDB 연결 성공'))
app.listen(3000, () => console.log('서버 시작: 포트 3000'))
모델 정의
스키마 설계는 데이터 구조와 유효성 검사의 기준이 된다. 예시로 간단한 게시물(Post) 모델을 정의한다.
const { Schema, model } = require('mongoose')
const postSchema = new Schema({
title: { type: String, required: true },
content: { type: String, required: true },
author: { type: String, default: 'anonymous' },
createdAt: { type: Date, default: Date.now }
})
const Post = model('Post', postSchema)
module.exports = Post
CRUD 구현
Express 라우터를 이용해 CRUD 엔드포인트를 구성한다. 각 동작의 예제와 간단한 설명을 함께 제공한다.
Create (생성)
새 문서 생성은 POST 요청으로 처리된다. 잘못된 요청은 400 오류로 응답한다.
app.post('/posts', async (req, res) => {
try {
const { title, content, author } = req.body
const post = new Post({ title, content, author })
const saved = await post.save()
res.status(201).json(saved)
} catch (err) {
res.status(400).json({ error: err.message })
}
})
Read (조회)
모든 문서 조회와 단일 문서 조회 예시를 포함한다. 쿼리 파라미터로 필터링이 가능하다.
// 전체 조회
app.get('/posts', async (req, res) => {
try {
const posts = await Post.find().sort({ createdAt: -1 })
res.json(posts)
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// 단일 조회
app.get('/posts/:id', async (req, res) => {
try {
const post = await Post.findById(req.params.id)
if (!post) return res.status(404).json({ error: 'Not found' })
res.json(post)
} catch (err) {
res.status(400).json({ error: err.message })
}
})
Update (수정)
부분 수정과 전체 교체 방식의 예제를 함께 제시한다. 반환 옵션을 통해 수정된 문서를 반환하도록 설정한다.
// 부분 수정
app.patch('/posts/:id', async (req, res) => {
try {
const updated = await Post.findByIdAndUpdate(
req.params.id,
{ $set: req.body },
{ new: true, runValidators: true }
)
if (!updated) return res.status(404).json({ error: 'Not found' })
res.json(updated)
} catch (err) {
res.status(400).json({ error: err.message })
}
})
Delete (삭제)
문서 삭제는 식별자를 사용해 수행된다. 삭제 결과에 따라 상태 코드를 반환한다.
app.delete('/posts/:id', async (req, res) => {
try {
const removed = await Post.findByIdAndDelete(req.params.id)
if (!removed) return res.status(404).json({ error: 'Not found' })
res.json({ message: '삭제 완료' })
} catch (err) {
res.status(400).json({ error: err.message })
}
})
실행 및 테스트 예시
서버 실행 후 curl 또는 Postman으로 간단히 테스트할 수 있다. 예시는 curl 명령을 사용한 요청 형태를 보여준다.
# 생성
curl -X POST http://localhost:3000/posts -H "Content-Type: application/json" -d '{"title":"제목","content":"내용"}'
# 전체 조회
curl http://localhost:3000/posts
# 단일 조회
curl http://localhost:3000/posts/{id}
# 수정
curl -X PATCH http://localhost:3000/posts/{id} -H "Content-Type: application/json" -d '{"title":"수정된 제목"}'
# 삭제
curl -X DELETE http://localhost:3000/posts/{id}
권장 사항 및 마무리
프로덕션 환경에서는 연결 문자열의 보안 관리, 적절한 타임아웃 설정, 에러 로깅, 입력 검증, 인덱스 설계가 중요하다. 트랜잭션이 필요한 작업은 세션 기반 트랜잭션을 고려한다. 이 문서는 기본 흐름을 이해하는 데 초점을 둔 정리 자료이다.
추가적으로 복잡한 쿼리 작성, 페이징 처리, 관계 데이터 모델링(populate) 등은 다음 단계로 확장하면 유용한 주제이다.