[Node.js-01] MongoDB Atlas & Node.js

Comely·2025년 3월 12일

Node.js

목록 보기
1/14

🗄️ 데이터베이스 기본 개념

데이터베이스가 필요한 이유

게시판을 만들려면 유저들이 작성한 게시물을 영구적으로 보관할 곳이 필요합니다. 메모장이나 엑셀로도 가능하지만, 실제 서비스에서는 데이터베이스를 사용합니다.

데이터베이스의 장점:

  • 빠른 입출력 속도
  • 대용량 데이터 보관 가능
  • 동시 접근 처리
  • 백업 및 복구 기능

📊 데이터베이스 종류

관계형 데이터베이스 (SQL)

사용자 테이블
+----+--------+-----+
| ID | 이름   | 나이|
+----+--------+-----+
| 1  | 김철수 | 25  |
| 2  | 이영희 | 30  |
+----+--------+-----+

주문 테이블
+----+---------+--------+
| ID | 사용자ID| 상품   |
+----+---------+--------+
| 1  | 1       | 노트북 |
| 2  | 2       | 마우스 |
+----+---------+--------+

특징:

  • 엑셀과 유사한 표 형태
  • 정규화: 중복 데이터 최소화
  • SQL 언어 사용
  • 높은 정확도

대표 DBMS:

  • MySQL
  • PostgreSQL
  • Oracle
  • SQLite

비관계형 데이터베이스 (NoSQL)

// MongoDB 문서 예시
{
  _id: ObjectId("..."),
  name: "김철수",
  age: 25,
  orders: [
    { product: "노트북", date: "2024-01-01" },
    { product: "마우스", date: "2024-01-02" }
  ]
}

특징:

  • 자유로운 데이터 구조
  • 빠른 입출력
  • 수평 확장 용이
  • JavaScript Object와 유사

대표 NoSQL:

  • MongoDB (Document)
  • Redis (Key-Value)
  • Cassandra (Column)

🍃 MongoDB 선택 이유

왜 MongoDB인가?

  1. 쉬운 사용법: SQL 학습 불필요
  2. JavaScript 친화적: Object 형태로 데이터 저장
  3. 유연한 스키마: 정규화 없이 자유롭게 저장
  4. 빠른 개발: 복잡한 설정 불필요

MongoDB 데이터 구조

Database (forum)
└── Collection (post)
    ├── Document { title: "첫 글", content: "내용1" }
    ├── Document { title: "두번째 글", content: "내용2" }
    └── Document { title: "세번째 글", content: "내용3" }

용어 정리:

  • Database: 프로젝트 (엑셀 파일)
  • Collection: 폴더 (엑셀 시트)
  • Document: 파일 (엑셀 행)

☁️ MongoDB Atlas 설정

1. 회원가입 & 초기설정

  1. 사이트 접속: mongodb.com 또는 "MongoDB Atlas" 검색
  2. 회원가입: 이메일 인증 필요
  3. 설문조사: 개발 목적으로 선택

2. 클러스터 생성

✅ 무료 티어 선택 (M0 Sandbox)
✅ 서버 위치: Seoul (ap-northeast-2)
✅ 클러스터 이름: 기본값 사용

3. 데이터베이스 접속 계정 생성

Database Access 메뉴:

  • 아이디/비밀번호 생성
  • 역할: Atlas Admin 선택 ⭐
  • 예시: admin / password123

⚠️ 주의: 이 계정은 몽고DB 로그인 계정과 다름

4. IP 주소 허용

Network Access 메뉴:

  • Add IP Address 클릭
  • Allow access from anywhere 선택
  • 또는 0.0.0.0/0 직접 입력

5. 데이터베이스 & 컬렉션 생성

Database 이름: forum
Collection 이름: post

Browse Collections → Create Database에서 생성

🔗 Node.js와 MongoDB 연결

1. MongoDB 드라이버 설치

npm install mongodb@5

2. 연결 URL 가져오기

Connect 버튼 → Drivers 선택:

mongodb+srv://DB접속아이디:DB접속비번@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority

3. 서버 코드 작성

const { MongoClient } = require('mongodb')

let db
const url = 'mongodb+srv://admin:password123@cluster0.xxxxx.mongodb.net/?retryWrites=true&w=majority'

new MongoClient(url).connect().then((client) => {
  console.log('DB연결성공')
  db = client.db('forum')
  
  // DB 연결 후 서버 시작
  app.listen(8080, () => {
    console.log('http://localhost:8080 에서 서버 실행중')
  })
}).catch((err) => {
  console.log('DB연결실패:', err)
})

💾 데이터 저장하기

Atlas 웹에서 직접 저장

Browse Collections → Insert Document:

// 첫 번째 문서
{
  title: "첫 게시물",
  content: "안녕하세요. 첫 번째 글입니다."
}

// 두 번째 문서
{
  title: "두번째 글임", 
  content: "MongoDB 좋네요"
}

서버에서 저장하기

app.get('/insert', (요청, 응답) => {
  db.collection('post').insertOne({
    title: '서버에서 저장한 글',
    content: '내용입니다'
  })
  응답.send('저장완료')
})

ObjectId 이해

{
  _id: ObjectId("507f1f77bcf86cd799439011"),
  title: "게시물 제목",
  content: "게시물 내용"
}

ObjectId 특징:

  • 자동 생성: 각 Document마다 고유 ID
  • 중복 없음: 전 세계에서 유일
  • 시간 정보: 생성 시간 포함
  • 수동 설정 가능: 1, 2, 3 등 숫자도 가능

데이터 저장 모범사례

// ❌ 나쁜 예: 하나의 문서에 모든 게시물
{
  posts: [
    { title: "글1", content: "내용1" },
    { title: "글2", content: "내용2" },
    // ... 100만 개의 글
  ]
}

// ✅ 좋은 예: 각각 별도 문서
{ title: "글1", content: "내용1" }
{ title: "글2", content: "내용2" }
{ title: "글3", content: "내용3" }

이유: MongoDB는 문서 찾기는 빠르지만, 문서 내 특정 데이터 찾기는 느림

📖 데이터 조회하기

기본 조회

app.get('/list', async (요청, 응답) => {
  let result = await db.collection('post').find().toArray()
  응답.send(result)
})

JavaScript 기초: Array & Object

Array (배열)

let 과일들 = ['사과', '바나나', '오렌지']

console.log(과일들[0])  // '사과'
console.log(과일들[1])  // '바나나'
console.log(과일들[2])  // '오렌지'

Object (객체)

let 사람 = { 
  name: '김철수', 
  age: 25,
  city: '서울'
}

console.log(사람.name)     // '김철수'
console.log(사람['age'])   // 25

DB 조회 결과 처리

// DB에서 가져온 데이터 형태
[
  {
    _id: ObjectId("..."),
    title: "첫 게시물",
    content: "내용1"
  },
  {
    _id: ObjectId("..."), 
    title: "두번째 글",
    content: "내용2"
  }
]

특정 데이터 추출

app.get('/list', async (요청, 응답) => {
  let result = await db.collection('post').find().toArray()
  
  // 첫 번째 글 제목
  console.log(result[0].title)
  
  // 두 번째 글 내용
  console.log(result[1].content)
  
  // 모든 글 제목
  result.forEach( => {
    console.log(.title)
  })
  
  응답.send(result[0].title)
})

⚡ Async/Await 이해

동기 vs 비동기

// 동기적 실행 (순서대로)
console.log('1번')
console.log('2번')
console.log('3번')

// 비동기적 실행
console.log('1번')
db.collection('post').find().toArray()  // 시간이 걸림
console.log('3번')  // DB 작업 완료 전에 실행됨

Async/Await 사용법

// ❌ 문제가 있는 코드
app.get('/list', (요청, 응답) => {
  let result = db.collection('post').find().toArray()
  console.log(result)  // Promise 객체 출력
  응답.send(result[0].title)  // 에러 발생
})

// ✅ 올바른 코드
app.get('/list', async (요청, 응답) => {
  let result = await db.collection('post').find().toArray()
  console.log(result)  // 실제 데이터 출력
  응답.send(result[0].title)  // 정상 작동
})

규칙:

  • await를 사용하려면 함수에 async 키워드 필요
  • await는 비동기 작업이 완료될 때까지 기다림

🎯 실전 예제

게시물 목록 API

app.get('/api/posts', async (요청, 응답) => {
  try {
    let posts = await db.collection('post').find().toArray()
    응답.json({
      success: true,
      data: posts,
      count: posts.length
    })
  } catch (error) {
    응답.status(500).json({
      success: false,
      message: '데이터 조회 실패',
      error: error.message
    })
  }
})

특정 게시물 조회

app.get('/api/posts/:id', async (요청, 응답) => {
  try {
    let { ObjectId } = require('mongodb')
    let post = await db.collection('post').findOne({
      _id: new ObjectId(요청.params.id)
    })
    
    if (post) {
      응답.json({ success: true, data: post })
    } else {
      응답.status(404).json({ success: false, message: '게시물을 찾을 수 없습니다' })
    }
  } catch (error) {
    응답.status(500).json({ success: false, error: error.message })
  }
})

새 게시물 저장

app.post('/api/posts', async (요청, 응답) => {
  try {
    let newPost = {
      title: 요청.body.title,
      content: 요청.body.content,
      author: 요청.body.author,
      createdAt: new Date()
    }
    
    let result = await db.collection('post').insertOne(newPost)
    
    응답.json({
      success: true,
      message: '게시물 저장 완료',
      insertedId: result.insertedId
    })
  } catch (error) {
    응답.status(500).json({ success: false, error: error.message })
  }
})

🔧 일반적인 MongoDB 조회 패턴

조건부 조회

// 특정 제목으로 검색
let result = await db.collection('post').find({ title: '첫 게시물' }).toArray()

// 작성자로 검색
let result = await db.collection('post').find({ author: '김철수' }).toArray()

// 여러 조건
let result = await db.collection('post').find({ 
  author: '김철수',
  title: /게시물/
}).toArray()

정렬 및 제한

// 최신순 정렬
let result = await db.collection('post')
  .find()
  .sort({ _id: -1 })
  .toArray()

// 개수 제한
let result = await db.collection('post')
  .find()
  .limit(5)
  .toArray()

// 건너뛰기 (페이징)
let result = await db.collection('post')
  .find()
  .skip(10)
  .limit(5)
  .toArray()

📝 요약 정리

핵심 개념

  1. 컬렉션 전체 조회: db.collection('컬렉션명').find().toArray()
  2. Array 데이터 추출: 배열[인덱스]
  3. Object 데이터 추출: 객체.속성명 또는 객체['속성명']
  4. 비동기 처리: async/await 사용 필수

다음 단계

  • HTML 페이지에 DB 데이터 표시하기
  • 사용자 입력 받아 DB에 저장하기
  • 게시물 수정/삭제 기능 구현
  • 페이징 및 검색 기능 추가
profile
App, Web Developer

0개의 댓글