본문 바로가기
Project/기타

Next.js에서 MongoDB Data 가져오기 / 웹 이력서

by 이의찬 2024. 3. 3.

1. Why?

최근에 취업을 위해서 Web으로 이력서를 만들었다. 회사에 지원할때 제출할 용도로 만들었기에 최대한 빠르게 구현하고자 했고, Project와 Experience등의 사용되는 Data를 src/data 폴더에 넣어두고 가져와서 쓰고 있었다. 하지만 이런 방식으로 구현하다 보니 여러 문제점이 생겼다.

  • 내용을 조금 바꿀때마다 새로 commit 하는것이 불편함
  • 다른 사람들이 변경 전의 내용을 모두 볼 수 있다는 점

마침 Next.js를 사용하는 김에 DB에서 직접 데이터를 가져와서 사용해보고 싶었기에, MongoDB를 사용해서 data를 가져와 사용하는 방식으로 변경하기로 결정했다.

MongoDB를 선택한 이유

몽고DB는 구글에 검색만 해도 연관검색어 맨 위에 쓰지말라는 말이 뜨는 아주 놀라운 DB이다. 그렇다면 나는 왜 이런 간청을 무시하고 몽고DB로 데이터를 만들었을까? 

쓰지 말라는 글을 찾아서 읽어봤는데, 그 당시(12년 전)에는 MongoDB가 나온지 3년밖에 지나지 않았었고 데이터 정합성 측면에서 불안함이 많으니 쓰지 말라는 글이였다. 현재는 많은 부분에서 개선이 이뤄졌기에 문제가 없다.

사실 MongoDB 사용을 결정한 가장 큰 이유는 내가 이미 모든 Data를 프로덕트에 Js 객체 형식으로 넣어서 사용하고 있었기 때문이다. MongoDB에서 지원하는 BSON 형식으로 변경하면 약간의 부분만 변경하면 되는데 굳이 관계형 DB 형식으로 바꿀 이유를 느끼지 못했다.


2. How?

I love Atlas

놀랍게도 MongoDB에서는 Atlas라는 플랫폼을 통해서 데이터를 바로 클라우드에 올릴 수 있도록 해준다. 심지어 AWS, Azure 및 Google Cloud 중 어떤 클라우드 서비스로 올릴지 선택도 가능하다. 나는 AWS를 선택했다. 

1. Atlas로 MongoDB에 Data 올리기

우선 위와 같이 Database를 만들어준 다음, Insert Document를 사용해서 JSON 형식의 데이터를 넣어주면 된다. Collection은 폴더, Document는 폴더 안의 파일로 생각하면 이해가 쉬울 것이다.

2. MongoDB에서 Data 가져오기

이렇게 Data 작성이 끝났다면, Next.js에서 Data를 가져와야한다. 우선 Database Access에서 유저를 추가한 다음, Deployment/Database에서 Connect를 누르면 코드를 보여준다.

import { MongoClient } from 'mongodb';

const url = process.env.MONGODB_URL;
if (!url) {
  throw new Error('The MONGODB_URL environment variable is not defined');
}
let connectDB: Promise<MongoClient>;

// 개발 중일땐 자주 재실행이 일어나기에 MongoClient.connect가 동시에 여러개 실행될 수 있음 -> DB 입출력 느려짐
// 이를 방지하기 위해 개발중일 경우 global이라는 전역변수 저장소에 보관

if (process.env.NODE_ENV === 'development') { 
  if (!global._mongo) {
    global._mongo = new MongoClient(url).connect();
  }
  connectDB = global._mongo;
} else {
  connectDB = new MongoClient(url).connect();
}
export { connectDB };
  • 위의 코드는 유저가 볼 수 없도록 server에서 돌아가는 것이 좋다.
  • MongoDB의 URL은 노출되면 안되기에 github에 올라가지 않도록 env파일에 넣고 gitignore에 추가해줘야한다.
import { connectDB } from '@/app/util/data';

// 생략...

const db = (await connectDB).db('Portfolio');
const exp = await db.collection<ExperienceResponse>('Exp').find().toArray();
const projects = await db
  .collection<ProjectResponse>('Projects')
  .find()
  .toArray();
const otherProjects = await db
  .collection<ProjectDefaultResponse>('otherProjects')
  .find()
  .toArray();
  
  export default function Home() {
  return (
    <main>
    // 생략...
      <Project projectData={projects} />
      <OtherProject projectData={otherProjects} />
      <Experience expData={exp} />
    </main>
  );
}
  • 나의 경우에는 최상단 컴포넌트인 Home에서 가져온 data를 하위 컴포넌트에 props로 전달하도록 해서 데이터를 하위 컴포넌트에서 여러번 불러오지 않도록 했다.
  • 다만 최상단 컴포넌트에서 await를 사용하는 것은 es2017 이후부터 가능한데, 현업에서 일하는 사람들이 그 이전의 브라우저를 사용할 가능성이 거의 없다고 생각했다.

Promise<MongoClient> type 이슈

global.d.ts파일을 만들어서 아래와 같이 전역 객체인 global에 _mongo: Promise<MongoClient> | undefined로 타입을 추가해주었다.

export {};
declare global {
  var _mongo: Promise<MongoClient> | undefined;
}

3. MongoDB와 Vercel 연결

이제 로컬 환경에서는 무사히 Data를 가져와서 실행할 수 있을 것이다. 그럼 배포 환경으로 넘어가보자.

 

나는 Next.js 개발사인 Vercel의 서비스를 통해서 배포를 했다. 무료인데다가 Next.js의 개발사이기에 프론트엔드 배포에 최적화되어 있고, 서버리스 아키텍쳐 기반이기에 서버 관리를 알아서 해준다는 장점이 있다. 또 MongoDB와의 연결도 매우 쉽다.

 

크게 두 가지 부분만 해주면 되는데, env 설정과 ip 설정이다.

1.  env

설정에서 위의 메뉴로 이동해 env의 Key값과 Value값을 입력해주면 된다.

2. ip

MongoDB 공식 홈페이지에 자세한 방법이 소개되어 있다. 마찬가지로 설정에서 Integrations으로 이동해 browser marketplace로 이동한 다음, MongoDB를 찾아서 Add Integrations을 해주면 된다.

 

혹시 이력서 사이트가 궁금하다면 아래의 링크로 접속하면 된다!

https://resume-legitgoons.vercel.app/

이력서를 Figma 기반으로 수정하면서 24.04 이후로 업데이트를 멈췄습니다. 참고 바랍니다. 

 


3. 래퍼런스

코딩애플 Next.js 13 강의

https://velog.io/@redjen/mongodb%EC%9D%98-16mb-%EC%95%85%EB%A7%88#mongodb-%EC%93%B0%EC%A7%80-%EB%A7%88%EC%84%B8%EC%9A%94

 

MongoDB의 16MB 악마

절이 싫으면 중이 떠나라?

velog.io

https://velog.io/@leejaylight/node%EC%9D%98-%EB%82%B4%EC%9E%A5-%EA%B0%9D%EC%B2%B4-global

 

[node] global 전역 객체

global은 전역 객체로, node 환경 내에서 모든 파일에서 접근 가능하고 내부의 메서드를 global 표기를 생략하고 사용이 가능하다. 내부에 message, console, 파일 간 간단한 데이터 공유에 활용할 수 있으

velog.io