안녕하세요! 오늘은 Node.js와 MongoDB를 사용할 때 데이터 삽입 과정에서 자주 발생하는 문제점들과 그 해결방법에 대해 이야기해보겠습니다.
문제 상황: "db is not defined" 오류

많은 개발자들이 처음 MongoDB를 사용할 때 겪는 가장 흔한 문제 중 하나가 바로 이 오류입니다.
해당 오류는 db라는 변수를 참조하지 못해서 발생하는오류입니다.
잘못된 코드 예시
const express = require('express')
const app = express()
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
async function main() {
await client.connect();
const db = client.db('forum'); // 함수 스코프 내에서만 유효
const collection = db.collection('documents');
return '성공';
}
main()
.then(console.log)
.catch(console.error)
.finally(() => client.close()); // 연결이 즉시 끊어짐
app.get('/news', (요청, 응답) => {
db.collection('post').insertOne({ // ❌ db is not defined!
title: '오늘의 날씨',
content: '맑음'
})
})
18번 라인까지는 mongodb npm에서 제공되는 예제코드입니다.(링크)
단순 디비를 조회하고 응답을 반환할때는 문제가 없지만 새로운 라우터를 생성하고 요청을 해야하는 상황에서 다음과 같은 문제가 발생합니다.
문제점 분석
- 스코프 문제:
db변수가main()함수 내부에서만 정의되어 라우트 핸들러에서 접근할 수 없음 - 연결 해제:
client.close()가 즉시 실행되어 데이터베이스 연결이 끊어짐 - 비동기 처리 부재: 데이터 삽입이 비동기 작업인데
await를 사용하지 않음 - 응답 누락: 클라이언트에게 응답을 보내지 않아 요청이 무한 대기
올바른 해결방법
전역 변수로 데이터베이스 연결 관리
const express = require('express')
const app = express()
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
// 전역 변수로 db 선언
let db;
async function main() {
await client.connect();
console.log('서버에 연결하였습니다.');
db = client.db('forum'); // 전역 변수에 할당
return '성공';
}
main()
.then(console.log)
.catch(console.error)
// 연결 유지를 위해 client.close() 제거
데이터 삽입비동기 처리와 에러 핸들링
app.get('/news', async (요청, 응답) => {
try {
const result = await db.collection('post').insertOne({
title: '오늘의 날씨',
content: '맑음'
});
응답.send('데이터가 성공적으로 추가되었습니다!');
} catch (error) {
console.error('오류:', error);
응답.status(500).send('서버 오류가 발생했습니다.');
}
})
코드 분석
1. async 키워드
app.get('/news', async (요청, 응답) => {
- 라우트 핸들러 함수 앞에
async를 붙이면 이 함수가 비동기 함수가 됩니다 - 비동기 함수 내에서만
await키워드를 사용할 수 있습니다
2. await 키워드
const result = await db.collection('post').insertOne({...});
await는 "기다려"라는 뜻입니다- 데이터베이스 작업이 완료될 때까지 기다린 후 다음 코드를 실행합니다
await없이db.collection('post').insertOne({...})만 쓰면 Promise 객체가 반환되어 즉시 다음 코드로 넘어갑니다
잠깐 그러면 'await'을 사용하면 중간에 대기해야하니까 동기 처리가 아닐까? 하는 생각이 들수 있습니다.
await은 해당 함수에서만 응답이올때까지 기다리고, 다른 함수들의 요청들은 계속 처리됩니다. 즉 위 코드에서 DB 작업은 백그라운드에서 실행되면서 Node.js는 다른 라우터 핸들러의 작업을 계속 받을 수 있습니다.
3. result 변수에 담는 이유
const result = await db.collection('post').insertOne({...});
insertOne()메서드는 삽입 결과 정보를 반환합니다result에는 다음과 같은 정보가 담깁니다.
{
acknowledged: true,
insertedId: ObjectId("..."), // 새로 생성된 문서의 ID
insertedCount: 1
}
4. 응답.send()로 응답 보내기
응답.send('데이터가 성공적으로 추가되었습니다!');
- Express.js에서 모든 HTTP 요청에는 반드시 응답을 보내야 합니다
- 응답을 보내지 않으면 브라우저가 무한 대기 상태가 됩니다
응답.send()는 클라이언트에게 텍스트, JSON, HTML 등을 전송합니다
5. try-catch로 에러 처리
try {
// 데이터베이스 작업
} catch (error) {
console.error('오류:', error);
응답.status(500).send('서버 오류가 발생했습니다.');
}
try블록에서 오류가 발생하면catch블록이 실행됩니다- 데이터베이스 연결 실패, 권한 문제, 네트워크 오류 등을 처리합니다
응답.status(500)은 HTTP 500 에러(서버 내부 오류)를 의미합니다