목차
1. MongoDB에 대해
2. MongoDBAtlas 생성
3. Node.js - MongoDB 연결
4. 모델(Model) 생성
1. MongoDB에 대해

MongoDB는 오픈소스 비관계형 데이터베이스 관리 시스템으로 테이블과 행 대신 유연한 문서를 활용해 다양한 데이터 형식을 처리하고 저장한다. NoSQL 기반 데이터베이스라고 하면 가장 대중적으로 많이 쓰이는 데이터베이스이기도 하다.
먼저 NoSQL은 기존의 RDBMS와 같은 관계형 모델을 지양하고 대량의 분산된 비정형 데이터를 저장 및 조회하는데 특화된 비관계형 데이터베이스를 지칭한다. 다음으로 NoSQL과 RDBMS와의 차이점을 짚고가자.
1. 구조 및 데이터 모델
RDBMS | NoSQL |
테이블 기반의 관계형 모델 | 여로 가지 데이터 모델 지원 (문서, 키-값, 그래프) |
엄격한 스키마가 필요, 데이터는 사전에 정의된 구조를 따름 | 스키마리스 또는 동적 스키마를 지원하여 유연한 데이터 구조를 따름 |
ex) MySQL, PostgreSQL, Oracle, SQL Server | ex) MongoDB (문서형), Redis(키-값), Neo4j(그래프) |
2. 일관성 및 가용성
RDBMS | NoSQL |
ACID 속성 : 트랜잭션이 원자성, 일관성, 고립성, 지속성 보장 | CAP 이론 : 일관성, 가용성, 네트워크 분할 허용 중 2가지 보장 |
일관성 중시 : 데이터의 일관성을 중시 | 유연성 : 특정 사용 사례에 따라 일관성보다 가용성을 중시 |
3. 사용 사례
RDBMS | NoSQL |
구조화된 데이터, 관계형 데이터 모델, 복잡한 쿼리 및 트랜잭션이 중요한 애플리케이션 | 비정형 데이터, 대규모 데이터 처리, 빠른 읽기/쓰기 성능이 중요한 애플리케이션 |
ex) 은행, ERP 시스템 | ex) 소셜 미디어, IoT, 빅데이터 분석 |
NoSQL의 사용 사례에서 알 수 있듯이 비정형 데이터나 대규모 데이터 처리에 적합하다.
프로젝트에서 실시간 채팅을 데이터를 저장하기 위해 NoSQL 데이터베이스 중 하나를 채택하기로 했고 가장 대중적인 MongoDB를 선택하게 되었다.
특히 로컬이 아닌 클라우드 데이터베이스를 사용하기 위해 MongoDB Atlas를 활용했고 이는 AWS의 MongoDB 클러스터를 실행할 수 있으며, 서버 프로비저닝 및 모니터링 그리고 백업/복구 등 인프라 관리를 자동적으로 지원해주는 장점이 있다.
2. MongoDBAtlas 생성 및 연결
MongoDB: 개발자 데이터 플랫폼
업계 최고의 최신 데이터베이스를 토대로 구축된 개발자 데이터 플랫폼을 사용해 아이디어를 더욱 빠르게 실현하세요. 공통 쿼리 인터페이스와 개발자들이 원하는 데이터 모델을 사용하는 동
www.mongodb.com
먼저 위의 링크에서 계정을 생성하고 생성할 타입을 확인한다.

무료 버전은 Shared로 최대 5GB의 storage를 무료로 사용할 수 있다. 자세한 옵션은 사이트에서 참고하길 바란다.
포스팅은 Shared를 기준으로 작성되었다.
(1) New Organization 생성

먼저 팀이 사용할 Organization을 생성하기 위해 Create New Organization을 클릭한다.


Organization 이름을 입력하고 MongoDB Atlas를 선택한다.
Github Organization에서 Member를 추가하는 것과 동일하게 초대하고 싶은 Member 이메일과 권한을 설정하고 Create Organization을 클릭해 생성을 완료한다.
(2) New Project 생성

Github Organization 내부에 Repository를 생성하는 것처럼, New Project를 클릭하여 생성한 Organization 내부에 Project를 만들어준다.


생성할 Project 이름을 입력하고 Next
초대할 Member의 메일과 권한을 입력하고 Create Project를 눌러 새로운 Project를 생성한다.
(3) Cluster 생성

프로젝트 생성이 완료되었다면 위와 같은 대시보드로 이동할 것이다.
이번엔 cluster 생성을 위해 Create를 클릭해준다.

먼저 무료버전인 M0(Shared)를 선택하고

Name을 설정해준다. 클러스터명은 생성 이후엔 변경할 수 없으니 신중한 명명이 필요하다.
MongoDB Atlas는 클라우드 제공자를 AWS, Google Cloud, Azure 중 선택할 수 있는데
Provider → AWS
Region → Seoul (ap-northeast-2)
위와 같이 선택해주었다. Region은 현재 위치 또는 현재와 가장 가까운 위치로 만들어주는 것이 좋다.
입력이 완료되었다면 옵션을 검토 후 Create Deployment를 선택해 Atlas Cluster를 생성한다.
(4) Connect
이제 Cluster가 생성되었으니 IP 주소에 대한 액세스 권한을 부여하고, 데이터베이스 유저를 생성해야한다.

대시보드 Cluster 영역에서 connect를 선택한다.

데이터베이스 접속을 위한 유저를 생성할 수 있다. 데이터베이스 생성 후 첫번째 유저는 atlasAdmin으로 관리자 계정을 의미한다.
즉 관리자 계정의 user, password를 생성하는 단계이다.

Node.js로 구축된 서버에서 MongoDB에 접근하기 위해서는 select client category를 Drivers로 선택한다.
이때 Driver는 Node.js로, 설치된 npm 버전에 맞는 Version을 선택한다.
이때 선택한 옵션에 맞게 오른쪽 섹션에서 Node.js 서버에서
① npm install mongodb로 mongodb 의존성을 주입받고
② string 형식의 db url을 제공한다.
3. Node.js - MongoDB 연결
프로젝트에서는 각종 환경 설정을 위한 dotenv와 mongodb를 쉽게 다룰 수 있는 기능을 제공하는 라이브러리 mongoose를 사용할 예정이다.
npm install mongoose
npm install dotenv
mongodb가 아닌 mongoose, dotenv 모듈의 설치가 필요하다.
Mongoose
MongoDB는 NoSQL이지만, 이를 연결해주는 Mongoose는 데이터 형태를 미리 정의하기 때문에 Schema를 사용한다.
Schema를 생성자를 이용해 생성하고, 이를 mongoose 객체의 model 메소드를 이용해 모델로 만든다.
해당 모델은 Node.js에서 객체의 형태로 가져와서 데이터를 찾거나 저장하는데 사용한다.
Q. 그런데 MongoDB 자체가 이미 Document이므로 JS인데 굳이 JS 객체와 매핑해주는걸까?
1. Schema 정의 및 검증
2. promise 문법과 가독성 높은 query 빌더 지원
3. RDBMS의 JOIN 기능을 populate 메소드로 보완
다음으로 데이터베이스 연결을 위한 config 파일과 민감 정보를 기록할 .env 파일이 필요한데, .env 파일엔 아래와 같은 3가지 속성이 작성되어 있어야 한다. 만약 dev와 prod로 개발 환경을 분리해두지 않았다면 NODE_ENV는 사용하지 않아도 무방하다.
Key | Value |
NODE_ENV | dev인지 prod인지를 구분 |
MONGO_DB_NAME | 생성한 cluster name |
MONGO_DB_URI | 위에서 생성한 string 형식의 db url |
.env 파일을 작성했다면 database.js를 생성하여 데이터베이스 연결을 위한 config 파일을 작성한다.
import dotenv from "dotenv";
import mongoose from "mongoose";
dotenv.config(); // .env 파일 사용 (환경 변수 관리)
const MONGO_URI = process.env.MONGO_URI;
const MONGO_DB_NAME = process.env.MONGO_DB_NAME;
export const connect = () => {
// dev 모드일 때, 실행 시 쿼리 출력 (디버깅 모드)
if (process.env.NODE_ENV !== "prod") {
mongoose.set("debug", true);
}
// mongodb://아이디:비밀번호@주소
mongoose
.connect(MONGO_URI, {
dbName: MONGO_DB_NAME,
useNewUrlParser: true,
})
.then(() => {
console.log("MongoDB connected!");
})
.catch((err) => {
console.error("MongoDB connection error", err);
});
};
mongoose.connection.on("error", (error) => {
console.error("MongoDB connection error", error);
});
mongoose.connection.on("disconnected", () => {
console.error("MongoDB connection has been lost! Attempting to reconnect.");
connect();
});
export default mongoose;
서버 코드가 실행될 때 항상 데이터베이스 연결이 유지될 수 있도록 시작 파일, 즉 index.js에서 database.js에서 connect를 import하여 호출해주는 부분이 필요하다. 아래 index.js의 일부를 작성해두었으니 본인 디렉토리 구조와 설계에 맞게 활용하면 좋을 것 같다.
import express from "express";
import { specs } from "./swagger/swagger.js";
import SwaggerUi from "swagger-ui-express";
import dotenv from "dotenv";
import cors from "cors";
import path from "path";
import { connect } from "./src/config/database.js";
dotenv.config(); // .env 파일 사용 (환경 변수 관리)
const app = express();
connect(); // mongodb 연결
// server setting - view, static, body-parser etc..
app.set("port", process.env.PORT || 3000); // 서버 포트 지정
app.use(cors()); // cors 방식 허용
app.use(express.static("public")); // 정적 파일 접근
app.use(express.json()); // request의 본문을 json으로 해석할 수 있도록 함 (JSON 형태의 요청 body를 파싱하기 위함)
app.use(express.urlencoded({ extended: false })); // 단순 객체 문자열 형태로 본문 데이터 해석
app.set("view engine", "ejs"); // 뷰 엔진을 EJS로 설정
app.use(express.static(path.join(__dirname, "src", "public")));
app.set("views", __dirname + "/src/view");
app.get("/", (req, res, next) => {
res.send(response(status.SUCCESS, "루트 페이지!"));
});
// error handling
app.use((req, res, next) => {
next(res.send(errResponse(status.NOT_FOUND)));
});
app.use((err, req, res, next) => {
// 템플릿 엔진 변수 설정
res.locals.message = err.message;
// 개발환경이면 에러를 출력하고 아니면 출력하지 않기
res.locals.error = process.env.NODE_ENV !== "prod" ? err : {};
console.error(err);
res
.status(err.data.status || status.INTERNAL_SERVER_ERROR)
.send(response(err.data));
});
const server = app.listen(app.get("port"), () => {
console.log(`Example app listening on port ${app.get("port")}`);
console.log(`Now env ` + process.env.NODE_ENV);
console.log(`Now REDIS_HOST ` + process.env.REDIS_HOST);
});
4. 모델(Model) 생성
다음은 모델 생성이다.
간단하게 user, chatRoom, chat을 예제로 확인해보자.
(1) user.js → "사용자" 스키마
import mongoose from "mongoose";
import jwt from "jsonwebtoken";
import dotenv from "dotenv";
const envFile = process.env.NODE_ENV === "prod" ? ".env.prod" : ".env.dev";
dotenv.config({ path: envFile }); // .env 파일 사용 (환경 변수 관리)
const secret = process.env.JWT_SECRET;
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const userSchema = new Schema(
{
email: {
type: String,
required: true,
unique: true,
index: true,
},
name: {
type: String,
required: true,
},
nickname: {
type: String,
required: true,
unique: true,
},
phone: {
type: String,
required: true,
unique: true,
},
birth: {
type: Date,
required: true,
},
profile_image: {
type: String,
},
password: {
type: String,
required: true,
},
// 포인트
point: {
type: Number,
default: 0,
},
// 포인트에 대한 배지
badge: {
type: String,
},
// 프리미엄 결제 여부
premium: {
payment: {
type: Boolean,
default: false,
required: true,
},
merchant_uid: {
type: String,
},
imp_uid: {
type: String,
},
updated_at: {
type: Date,
default: Date.now,
},
},
// 소속 크루
crew: {
type: ObjectId,
ref: "Crew",
},
// 상태
status: {
type: String,
required: true,
default: "active",
},
created_at: {
type: Date,
default: Date.now,
},
updated_at: {
type: Date,
default: Date.now,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X
);
const User = mongoose.model("User", userSchema);
export default User;
(2) chatRoom.js → "채팅방" 스키마
import mongoose from "mongoose";
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const chatRoomSchema = new Schema(
{
// 채팅 참여자
joiner: [
{
type: ObjectId,
ref: "User",
},
],
// 채팅방 종류
type: {
type: String,
/*
free = 자유 라이브
ing = 나 지금 헌혈 중 라이브
story = 헌혈 이야기 공유 라이브
crew = 크루
blood = 지정헌혈
*/
enum: ["free", "ing", "story", "crew", "blood"], //
required: true,
},
// 채팅방 이름
title: {
type: String,
required: true,
},
// 생성일
created_at: {
type: Date,
default: Date.now,
required: true,
},
// 수정일
updated_at: {
type: Date,
default: Date.now,
required: true,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X);
);
const ChatRoom = mongoose.model("ChatRoom", chatRoomSchema);
export default ChatRoom;
(3) chat.js → "채팅" 스키마
import mongoose from "mongoose";
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const chatSchema = new Schema(
{
// 채팅방
chatRoom: {
type: ObjectId,
required: true,
ref: "ChatRoom",
},
// 채팅 작성자
writer: {
id: {
type: ObjectId,
required: true,
ref: "User",
},
nickname: {
type: String,
required: true,
},
},
// 메시지
message: {
type: String,
required: false,
},
// 이미지 (S3 업로드 URL)
image: {
type: String,
required: false,
},
// 생성일
created_at: {
type: Date,
default: Date.now,
required: false,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X);
);
const Chat = mongoose.model("Chat", chatSchema);
export default Chat;
NoSQL은 RDBMS와 다르게 관계형이 아니기 때문에 스키마의 유연성과 읽기 성능의 최적화를 위해 데이터 중복을 허용한다.
예를 들어 채팅 스키마에서 RDBMS라면 채팅 작성자의 Long 타입 기본키 id를 외래키로 저장한다면, MongoDB에서는 외래키와 더불와 읽기 성능 최적화를 위해 nickname도 함께 저장한다.
versionKey는 default가 true로 설정되어 있기 때문에, 데이터 삽입 시 __v 칼럼이 자동으로 생성된다. 만약 생성하고 싶지 않다면 versionKey: false 속성을 추가해주어야 한다.
다음편에서는 쿼리 작성법에 대해 다룰 예정이며, 자세한 설정과 코드가 궁금하다면 아래 깃허브를 참고하길 바란다!
https://github.com/aeeazip/bloodtrail-be
GitHub - aeeazip/bloodtrail-be: bloodtrail backend repository
bloodtrail backend repository. Contribute to aeeazip/bloodtrail-be development by creating an account on GitHub.
github.com
'Framework > Node.js' 카테고리의 다른 글
[Node.js] Socket.io 실시간 채팅 서비스 - 서버 구축 (1) (1) | 2024.09.05 |
---|
목차
1. MongoDB에 대해
2. MongoDBAtlas 생성
3. Node.js - MongoDB 연결
4. 모델(Model) 생성
1. MongoDB에 대해

MongoDB는 오픈소스 비관계형 데이터베이스 관리 시스템으로 테이블과 행 대신 유연한 문서를 활용해 다양한 데이터 형식을 처리하고 저장한다. NoSQL 기반 데이터베이스라고 하면 가장 대중적으로 많이 쓰이는 데이터베이스이기도 하다.
먼저 NoSQL은 기존의 RDBMS와 같은 관계형 모델을 지양하고 대량의 분산된 비정형 데이터를 저장 및 조회하는데 특화된 비관계형 데이터베이스를 지칭한다. 다음으로 NoSQL과 RDBMS와의 차이점을 짚고가자.
1. 구조 및 데이터 모델
RDBMS | NoSQL |
테이블 기반의 관계형 모델 | 여로 가지 데이터 모델 지원 (문서, 키-값, 그래프) |
엄격한 스키마가 필요, 데이터는 사전에 정의된 구조를 따름 | 스키마리스 또는 동적 스키마를 지원하여 유연한 데이터 구조를 따름 |
ex) MySQL, PostgreSQL, Oracle, SQL Server | ex) MongoDB (문서형), Redis(키-값), Neo4j(그래프) |
2. 일관성 및 가용성
RDBMS | NoSQL |
ACID 속성 : 트랜잭션이 원자성, 일관성, 고립성, 지속성 보장 | CAP 이론 : 일관성, 가용성, 네트워크 분할 허용 중 2가지 보장 |
일관성 중시 : 데이터의 일관성을 중시 | 유연성 : 특정 사용 사례에 따라 일관성보다 가용성을 중시 |
3. 사용 사례
RDBMS | NoSQL |
구조화된 데이터, 관계형 데이터 모델, 복잡한 쿼리 및 트랜잭션이 중요한 애플리케이션 | 비정형 데이터, 대규모 데이터 처리, 빠른 읽기/쓰기 성능이 중요한 애플리케이션 |
ex) 은행, ERP 시스템 | ex) 소셜 미디어, IoT, 빅데이터 분석 |
NoSQL의 사용 사례에서 알 수 있듯이 비정형 데이터나 대규모 데이터 처리에 적합하다.
프로젝트에서 실시간 채팅을 데이터를 저장하기 위해 NoSQL 데이터베이스 중 하나를 채택하기로 했고 가장 대중적인 MongoDB를 선택하게 되었다.
특히 로컬이 아닌 클라우드 데이터베이스를 사용하기 위해 MongoDB Atlas를 활용했고 이는 AWS의 MongoDB 클러스터를 실행할 수 있으며, 서버 프로비저닝 및 모니터링 그리고 백업/복구 등 인프라 관리를 자동적으로 지원해주는 장점이 있다.
2. MongoDBAtlas 생성 및 연결
MongoDB: 개발자 데이터 플랫폼
업계 최고의 최신 데이터베이스를 토대로 구축된 개발자 데이터 플랫폼을 사용해 아이디어를 더욱 빠르게 실현하세요. 공통 쿼리 인터페이스와 개발자들이 원하는 데이터 모델을 사용하는 동
www.mongodb.com
먼저 위의 링크에서 계정을 생성하고 생성할 타입을 확인한다.

무료 버전은 Shared로 최대 5GB의 storage를 무료로 사용할 수 있다. 자세한 옵션은 사이트에서 참고하길 바란다.
포스팅은 Shared를 기준으로 작성되었다.
(1) New Organization 생성

먼저 팀이 사용할 Organization을 생성하기 위해 Create New Organization을 클릭한다.


Organization 이름을 입력하고 MongoDB Atlas를 선택한다.
Github Organization에서 Member를 추가하는 것과 동일하게 초대하고 싶은 Member 이메일과 권한을 설정하고 Create Organization을 클릭해 생성을 완료한다.
(2) New Project 생성

Github Organization 내부에 Repository를 생성하는 것처럼, New Project를 클릭하여 생성한 Organization 내부에 Project를 만들어준다.


생성할 Project 이름을 입력하고 Next
초대할 Member의 메일과 권한을 입력하고 Create Project를 눌러 새로운 Project를 생성한다.
(3) Cluster 생성

프로젝트 생성이 완료되었다면 위와 같은 대시보드로 이동할 것이다.
이번엔 cluster 생성을 위해 Create를 클릭해준다.

먼저 무료버전인 M0(Shared)를 선택하고

Name을 설정해준다. 클러스터명은 생성 이후엔 변경할 수 없으니 신중한 명명이 필요하다.
MongoDB Atlas는 클라우드 제공자를 AWS, Google Cloud, Azure 중 선택할 수 있는데
Provider → AWS
Region → Seoul (ap-northeast-2)
위와 같이 선택해주었다. Region은 현재 위치 또는 현재와 가장 가까운 위치로 만들어주는 것이 좋다.
입력이 완료되었다면 옵션을 검토 후 Create Deployment를 선택해 Atlas Cluster를 생성한다.
(4) Connect
이제 Cluster가 생성되었으니 IP 주소에 대한 액세스 권한을 부여하고, 데이터베이스 유저를 생성해야한다.

대시보드 Cluster 영역에서 connect를 선택한다.

데이터베이스 접속을 위한 유저를 생성할 수 있다. 데이터베이스 생성 후 첫번째 유저는 atlasAdmin으로 관리자 계정을 의미한다.
즉 관리자 계정의 user, password를 생성하는 단계이다.

Node.js로 구축된 서버에서 MongoDB에 접근하기 위해서는 select client category를 Drivers로 선택한다.
이때 Driver는 Node.js로, 설치된 npm 버전에 맞는 Version을 선택한다.
이때 선택한 옵션에 맞게 오른쪽 섹션에서 Node.js 서버에서
① npm install mongodb로 mongodb 의존성을 주입받고
② string 형식의 db url을 제공한다.
3. Node.js - MongoDB 연결
프로젝트에서는 각종 환경 설정을 위한 dotenv와 mongodb를 쉽게 다룰 수 있는 기능을 제공하는 라이브러리 mongoose를 사용할 예정이다.
npm install mongoose
npm install dotenv
mongodb가 아닌 mongoose, dotenv 모듈의 설치가 필요하다.
Mongoose
MongoDB는 NoSQL이지만, 이를 연결해주는 Mongoose는 데이터 형태를 미리 정의하기 때문에 Schema를 사용한다.
Schema를 생성자를 이용해 생성하고, 이를 mongoose 객체의 model 메소드를 이용해 모델로 만든다.
해당 모델은 Node.js에서 객체의 형태로 가져와서 데이터를 찾거나 저장하는데 사용한다.
Q. 그런데 MongoDB 자체가 이미 Document이므로 JS인데 굳이 JS 객체와 매핑해주는걸까?
1. Schema 정의 및 검증
2. promise 문법과 가독성 높은 query 빌더 지원
3. RDBMS의 JOIN 기능을 populate 메소드로 보완
다음으로 데이터베이스 연결을 위한 config 파일과 민감 정보를 기록할 .env 파일이 필요한데, .env 파일엔 아래와 같은 3가지 속성이 작성되어 있어야 한다. 만약 dev와 prod로 개발 환경을 분리해두지 않았다면 NODE_ENV는 사용하지 않아도 무방하다.
Key | Value |
NODE_ENV | dev인지 prod인지를 구분 |
MONGO_DB_NAME | 생성한 cluster name |
MONGO_DB_URI | 위에서 생성한 string 형식의 db url |
.env 파일을 작성했다면 database.js를 생성하여 데이터베이스 연결을 위한 config 파일을 작성한다.
import dotenv from "dotenv";
import mongoose from "mongoose";
dotenv.config(); // .env 파일 사용 (환경 변수 관리)
const MONGO_URI = process.env.MONGO_URI;
const MONGO_DB_NAME = process.env.MONGO_DB_NAME;
export const connect = () => {
// dev 모드일 때, 실행 시 쿼리 출력 (디버깅 모드)
if (process.env.NODE_ENV !== "prod") {
mongoose.set("debug", true);
}
// mongodb://아이디:비밀번호@주소
mongoose
.connect(MONGO_URI, {
dbName: MONGO_DB_NAME,
useNewUrlParser: true,
})
.then(() => {
console.log("MongoDB connected!");
})
.catch((err) => {
console.error("MongoDB connection error", err);
});
};
mongoose.connection.on("error", (error) => {
console.error("MongoDB connection error", error);
});
mongoose.connection.on("disconnected", () => {
console.error("MongoDB connection has been lost! Attempting to reconnect.");
connect();
});
export default mongoose;
서버 코드가 실행될 때 항상 데이터베이스 연결이 유지될 수 있도록 시작 파일, 즉 index.js에서 database.js에서 connect를 import하여 호출해주는 부분이 필요하다. 아래 index.js의 일부를 작성해두었으니 본인 디렉토리 구조와 설계에 맞게 활용하면 좋을 것 같다.
import express from "express";
import { specs } from "./swagger/swagger.js";
import SwaggerUi from "swagger-ui-express";
import dotenv from "dotenv";
import cors from "cors";
import path from "path";
import { connect } from "./src/config/database.js";
dotenv.config(); // .env 파일 사용 (환경 변수 관리)
const app = express();
connect(); // mongodb 연결
// server setting - view, static, body-parser etc..
app.set("port", process.env.PORT || 3000); // 서버 포트 지정
app.use(cors()); // cors 방식 허용
app.use(express.static("public")); // 정적 파일 접근
app.use(express.json()); // request의 본문을 json으로 해석할 수 있도록 함 (JSON 형태의 요청 body를 파싱하기 위함)
app.use(express.urlencoded({ extended: false })); // 단순 객체 문자열 형태로 본문 데이터 해석
app.set("view engine", "ejs"); // 뷰 엔진을 EJS로 설정
app.use(express.static(path.join(__dirname, "src", "public")));
app.set("views", __dirname + "/src/view");
app.get("/", (req, res, next) => {
res.send(response(status.SUCCESS, "루트 페이지!"));
});
// error handling
app.use((req, res, next) => {
next(res.send(errResponse(status.NOT_FOUND)));
});
app.use((err, req, res, next) => {
// 템플릿 엔진 변수 설정
res.locals.message = err.message;
// 개발환경이면 에러를 출력하고 아니면 출력하지 않기
res.locals.error = process.env.NODE_ENV !== "prod" ? err : {};
console.error(err);
res
.status(err.data.status || status.INTERNAL_SERVER_ERROR)
.send(response(err.data));
});
const server = app.listen(app.get("port"), () => {
console.log(`Example app listening on port ${app.get("port")}`);
console.log(`Now env ` + process.env.NODE_ENV);
console.log(`Now REDIS_HOST ` + process.env.REDIS_HOST);
});
4. 모델(Model) 생성
다음은 모델 생성이다.
간단하게 user, chatRoom, chat을 예제로 확인해보자.
(1) user.js → "사용자" 스키마
import mongoose from "mongoose";
import jwt from "jsonwebtoken";
import dotenv from "dotenv";
const envFile = process.env.NODE_ENV === "prod" ? ".env.prod" : ".env.dev";
dotenv.config({ path: envFile }); // .env 파일 사용 (환경 변수 관리)
const secret = process.env.JWT_SECRET;
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const userSchema = new Schema(
{
email: {
type: String,
required: true,
unique: true,
index: true,
},
name: {
type: String,
required: true,
},
nickname: {
type: String,
required: true,
unique: true,
},
phone: {
type: String,
required: true,
unique: true,
},
birth: {
type: Date,
required: true,
},
profile_image: {
type: String,
},
password: {
type: String,
required: true,
},
// 포인트
point: {
type: Number,
default: 0,
},
// 포인트에 대한 배지
badge: {
type: String,
},
// 프리미엄 결제 여부
premium: {
payment: {
type: Boolean,
default: false,
required: true,
},
merchant_uid: {
type: String,
},
imp_uid: {
type: String,
},
updated_at: {
type: Date,
default: Date.now,
},
},
// 소속 크루
crew: {
type: ObjectId,
ref: "Crew",
},
// 상태
status: {
type: String,
required: true,
default: "active",
},
created_at: {
type: Date,
default: Date.now,
},
updated_at: {
type: Date,
default: Date.now,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X
);
const User = mongoose.model("User", userSchema);
export default User;
(2) chatRoom.js → "채팅방" 스키마
import mongoose from "mongoose";
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const chatRoomSchema = new Schema(
{
// 채팅 참여자
joiner: [
{
type: ObjectId,
ref: "User",
},
],
// 채팅방 종류
type: {
type: String,
/*
free = 자유 라이브
ing = 나 지금 헌혈 중 라이브
story = 헌혈 이야기 공유 라이브
crew = 크루
blood = 지정헌혈
*/
enum: ["free", "ing", "story", "crew", "blood"], //
required: true,
},
// 채팅방 이름
title: {
type: String,
required: true,
},
// 생성일
created_at: {
type: Date,
default: Date.now,
required: true,
},
// 수정일
updated_at: {
type: Date,
default: Date.now,
required: true,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X);
);
const ChatRoom = mongoose.model("ChatRoom", chatRoomSchema);
export default ChatRoom;
(3) chat.js → "채팅" 스키마
import mongoose from "mongoose";
const { Schema } = mongoose;
const {
Types: { ObjectId },
} = Schema;
const chatSchema = new Schema(
{
// 채팅방
chatRoom: {
type: ObjectId,
required: true,
ref: "ChatRoom",
},
// 채팅 작성자
writer: {
id: {
type: ObjectId,
required: true,
ref: "User",
},
nickname: {
type: String,
required: true,
},
},
// 메시지
message: {
type: String,
required: false,
},
// 이미지 (S3 업로드 URL)
image: {
type: String,
required: false,
},
// 생성일
created_at: {
type: Date,
default: Date.now,
required: false,
},
},
{ versionKey: false } // 데이터 삽입 시 __v 칼럼 생성 X);
);
const Chat = mongoose.model("Chat", chatSchema);
export default Chat;
NoSQL은 RDBMS와 다르게 관계형이 아니기 때문에 스키마의 유연성과 읽기 성능의 최적화를 위해 데이터 중복을 허용한다.
예를 들어 채팅 스키마에서 RDBMS라면 채팅 작성자의 Long 타입 기본키 id를 외래키로 저장한다면, MongoDB에서는 외래키와 더불와 읽기 성능 최적화를 위해 nickname도 함께 저장한다.
versionKey는 default가 true로 설정되어 있기 때문에, 데이터 삽입 시 __v 칼럼이 자동으로 생성된다. 만약 생성하고 싶지 않다면 versionKey: false 속성을 추가해주어야 한다.
다음편에서는 쿼리 작성법에 대해 다룰 예정이며, 자세한 설정과 코드가 궁금하다면 아래 깃허브를 참고하길 바란다!
https://github.com/aeeazip/bloodtrail-be
GitHub - aeeazip/bloodtrail-be: bloodtrail backend repository
bloodtrail backend repository. Contribute to aeeazip/bloodtrail-be development by creating an account on GitHub.
github.com
'Framework > Node.js' 카테고리의 다른 글
[Node.js] Socket.io 실시간 채팅 서비스 - 서버 구축 (1) (1) | 2024.09.05 |
---|