Next.js 애플리케이션에서 MongoDB에 연결하는 방법에는 두 가지가 있다. MongoClient
를 사용하는 방법과 Mongoose
를 사용하는 방법이다. 이 블로그 글에서는 두 가지 방법을 모두 다룰 것이다.
먼저, MongoClient
를 이용하여 MongoDB에 연결하는 방법을 살펴보겠다.
import { MongoClient } from 'mongodb';
const uri = process.env.MONGODB_URI || '';
const options = {}
if (!uri) {
throw new Error('Please add your Mongo URI to .env local');
}
let client;
let clientPromise: Promise<MongoClient>;
if (process.env.NODE_ENV === 'development') {
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
export default clientPromise;
import { MongoClient } from 'mongodb';
mongodb
패키지에서 MongoClient
를 가져온다. 이를 통해 MongoDB 클라이언트를 생성할 수 있다.
const uri = process.env.MONGODB_URI || '';
const options = {}
console.log('MONGODB_URI: ', uri);
환경 변수 MONGODB_URI
에서 MongoDB URI 를 가져오고, 이 URI 가 설정되지 않은 경우 빈 문자열을 기본값으로 사용한다. 연결 옵션은 빈 객체로 설정되어 있다. 또한, URI 를 콘솔에 출력하여 확인한다.
if (!uri) {
throw new Error('Please add your Mongo URI to .env local');
}
URI 가 비어 있는 경우, 에러를 발생시켜 사용자가 올바른 URI 를 설정하지 않았음을 알린다.
let client;
let clientPromise: Promise<MongoClient>;
MongoDB 클라이언트와 클라이언트 연결 프라미스를 저장할 변수를 선언한다.
if (process.env.NODE_ENV === 'development') {
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
개발 환경 (process.env.NODE_ENV === 'development'
) 에서는 전역 객체 global
에 MongoClient
연결 프라미스를 저장한다. 이렇게 하면 개발 환경에서 코드가 여러 번 실행되더라도 같은 연결을 재사용할 수 있다.
global._mongoClientPromise
가 설정되지 않은 경우, 새로운 클라이언트를 생성하고 연결한다.
개발 환경이 아닐 때는, 클라이언트를 생성하고 바로 연결한다.
export default clientPromise;
clientPromise
를 기본 내보내기로 설정하여 다른 모듈에서 이 클라이언트를 사용할 수 있게 한다.
다음은 Mongoose
를 이용하여 MongoDB에 연결하는 방법이다.
import mongoose from 'mongoose';
const connection = {};
export const connectToDb = async () => {
try {
if (connection.isConnected) {
console.log('Using existing connection');
return;
}
const db = await mongoose.connect(process.env.MONGO);
connection.isConnected = db.connections[0].readyState;
} catch (error) {
console.log(error);
throw new Error(error);
}
};
import Mongoose from 'mongoose';
mongoose
패키지를 가져와 MongoDB와 상호작용할 수 있는 도구를 제공한다.
const connection = {};
연결 상태를 저장하기 위한 객체를 선언한다.
export const connectToDb = async() => {
try {
if (connection.isConnected) {
console.log("Using existing connection");
return;
}
const db = await mongoose.connect(process.env.MONGODB);
connection.isConnected = db.connections[0].readyState;
} catch (err) {
console.error(err);
throw new Error(err);
}
};
mongoose.connect
를 통해 MongoDB에 연결한다.직접적인 제어
MongoClient는 MongoDB의 기본 클라이언트 라이브러리로, MongoDB와의 상호작용을 직접 제어할 수 있다. 이를 통해 최적화된 쿼리와 데이터베이스 작업을 수행할 수 있다.
경량
MongoClient는 가벼운 라이브러리로, 추가적인 추상화 계층이 없다. 따라서 메모리 사용량이 적고, 성능이 빠르다.
유연성
MongoDB의 모든 기능을 직접 활용할 수 있으며, 피룡한 기능을 선택적으로 사용할 수 있다.
추가 코드 필요
데이터 모델링, 스키마 관리, 검증 등의 작업을 직접 구현해야 하므로 코드 작성량이 증가할 수 있다.
복잡성 증가
복잡한 쿼리나 데이터 변환을 처리할 때 추가적인 로직이 필요하므로, 코드가 복잡해질 수 있다.
스키마 기반 모델링
Mongoose는 스키마 기반 데이터 모델링을 제공하여 데이터 구조를 명확하게 정의하고, 데이터의 일관성을 유지할 수 있다.
내장 검증 및 후크
데이터 유효성 검사를 자동으로 수행하고, 데이터베이스 작업 전후에 실행되는 후크(hook)를 지원한다. 이를 통해 데이터 무결성을 보장할 수 있다.
편리한 쿼리 API
Mongoose는 MongoDB 쿼리를 보다 간결하게 작성할 수 있는 API를 제공한다. 이를 통해 복잡한 쿼리도 쉽게 작성할 수 있다.
가상 필드 및 메소드
스키마에 가상 필드와 커스텀 메소드를 추가하여 데이터를 가공하거나 확장할 수 있다.
추상화 오버헤드
Mongoose는 MongoDB 위에 추가적인 추상화 계층을 두기 때문에, 성능이 조금 저하될 수 있다.
추가 학습 필요
Mongoose의 고유한 문법과 기능을 익혀야 하므로, 초기 학습 비용이 발생할 수 있다.
유연성 감소
스키마 기반 모델링으로 인해, 스키마를 유연하게 변경하거나 동적 데이터를 처리하는 데 제약이 있을 수 있다.
MongoClient는 MongoDB와의 상호작용을 직접 제어하고 싶고, 추가적인 추상화 없이 경량의 클라이언트를 선호하는 경우에 적합하다. 예를 들어, 간단한 CRUD 애플리케이션이나 특정 성능 최적화가 필요한 경우에 유용하다.
Mongoose는 스키마 데이터 모델링, 데이터 검증, 편리한 쿼리 API 등을 제공하므로, 데이터 구조가 명확하고 복잡한 비즈니스 로직을 구현하는 데 유리하다. 예를 들어, 대규모 애플리케이션이나 데이터 무결성이 중요한 프로젝트에서 유용하다.
이 글에서는 Next.js 애플리케이션에서 MongoDB에 연결하는 두 가지 방법을 소개했다.
MongoClient
와 Mongoose
를 사용한 방법 모두 장단점이 있으므로, 프로젝트의 필요에 따라 적절한 방법을 선택하면 된다.