1. MongoDB
NoSql의 철학
유연성: (schema-less) 데이터 구조를 통한 다양한 데이터 유형을 쉽게 저장
수평적 확장성: 샤딩을 활용한 분산 저장으로 대규모 데이터 처리에 적합
고속 성능: 관계형 데이터베이스에 비해 읽기 및 쓰기 작업에서 더 높은 성능 제공
실시간 애플리케이션, 로그 데이터 등 처리에 유리
Document 모델
MongoDB는 데이터 객체를 JSON과 유사한 BSON(Binary JSON) 형식으로 저장한다.
데이터 스키마를 사전 정의할 필요가 없다.
각 Document는 유연한 구조를 가진다.
sql과 비교하자면 아래와 같다
Table <-> Collection
Row <-> Document
CRUD 작업
- Create: 데이터를 삽입 (db.collection.insertOne, db.collection.insertMany).
- Read: 데이터를 검색 (db.collection.find, 필터링 및 정렬).
- Update: 데이터를 갱신 (db.collection.updateOne, db.collection.updateMany).
- Delete: 데이터를 삭제 (db.collection.deleteOne, db.collection.deleteMany).
인덱싱
- 인덱스는 쿼리 성능을 높이는 핵심 요소.
- 단일 필드 인덱스: 한 필드에만 적용.
- 복합 인덱스: 여러 필드 조합에 적용.
- 텍스트 인덱스: 텍스트 검색에 최적화.
- TTL(Time-To-Live) 인덱스: 일정 시간이 지난 데이터를 자동 삭제.
- 성능 분석: db.collection.explain() 명령어로 쿼리 계획 확인.
샤딩
- 수평 확장을 통해 데이터를 여러 서버에 분산.
- 샤드 키(Shard Key):
- 데이터를 분산 저장할 기준 필드.
- 신중히 설계하지 않으면 데이터가 고르게 분산되지 않을 위험.
- 샤드 클러스터 구성 요소:
- Config Server: 샤드 메타데이터 저장.
- Query Router(Mongos): 클라이언트 요청을 적절한 샤드로 라우팅.
- Shard: 실제 데이터를 저장하는 노드.
- (샤딩 같은 경우 실제로 써봐야 이해할 수 있을 것 같다ㅠ)
운영 및 관리
- 백업과 복구:
- mongodump, mongorestore 사용법.
- 스냅샷 기반 백업을 통한 고속 복구.
- 모니터링:
- Prometheus & Grafana:
- 실시간 성능 모니터링 및 시각화.
- MongoDB의 기본 제공 도구:
- mongostat, mongotop.
- Prometheus & Grafana:
Mongoose
- Node.js 애플리케이션에서 MongoDB를 더 쉽게 사용할 수 있도록 도와주는 Object Data Modeling(ODM) 라이브러리
MongoDB 자체는 데이터베이스이지만, Mongoose는 이를 다루기 위한 고수준의 기능들을 제공 - 장점:
- 스키마 정의로 데이터 구조 제어.
- 유효성 검사 및 데이터 미들웨어 제공.
- 기능:
- Schema, Model을 통해 데이터 조작 간소화.
- 가독성 높은 비즈니스 로직 작성 가능.
- Schema 기반
- mongoose를 사용하면 데이터를 구조적으로 정의해둘 수 있다.
- 몽고 디비(스키마리스)를 쓰면서도 데이터 모델을 엄격히 정의할 수 있다.
2. NoSQL, SQL
https://sihanni.tistory.com/67
4. 설치
mongoDB, mongoExpress 도커를 통해 설치
로컬환경에서 단일 호스트로 여러 컨테이너를 작업하기 때문에 docker compose를 사용
version: '3.8'
services:
mongodb:
image: mongo:latest
container_name: mongodb
restart: always
ports:
- '27017:27017'
volumes:
- data:/data/db
environment:
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=0000
mongo-express:
image: mongo-express:latest
container_name: mongo-express
restart: always
ports:
- '8081:8081'
environment:
- ME_CONFIG_BASICAUTH_PASSWORD=admin
- ME_CONFIG_BASICAUTH_USERNAME=admin
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=0000
- ME_CONFIG_MONGODB_SERVER=mongodb
- ME_CONFIG_MONGODB_PORT=27017
depends_on:
- mongodb
volumes:
data: {}
networks:
default:
name: mongodb_network
docker exec -it mongodb mongosh 를 통해 컨테이너로 들어가서 접속을 확인하자
*mongosh
mongosh는 MongoDB Shell의 최신 버전으로, MongoDB와 상호작용할 수 있는 CLI 도구
test> use admin
switched to db admin
admin> db.auth("admin", "0000")
{ ok: 1 }
admin>
로컬 연결 확인
nestJS (mongoose 사용) 연결 확인
// app.module.ts
MongooseModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
uri: `mongodb://${configService.get<string>('MONGO_INITDB_ROOT_USERNAME')}:${configService.get<string>('MONGO_INITDB_ROOT_PASSWORD')}@${configService.get<string>('MONGO_HOST')}:${configService.get<number>('MONGO_PORT')}/${configService.get<string>('MONGO_DATABASE')}?authSource=admin`,
}),
}),
위와 같이 연결하면 된다.
이때 중요한건 뒤에 붙여준 ?authSource=admin 부분이다.
MONGO_INITDB_ROOT_USERNAME과 MONGO_INITDB_ROOT_PASSWORD는 기본적으로 admin 데이터베이스에 저장된 관리자 계정의 정보일 가능성이 있어 내가 채팅 데이터를 저장하려는 chat데이터베이스에 접속은 하되, 인증을 admin데이터베이스에서 수행하도록 설정하기 위해 명시적으로 authSource 옵션을 사용해주었다.
5. 코드내 사용
mongoose를 사용하기 위해선 우선 Schema를 작성해주어야한다.
몽구스는 스키마 기반이라고 배웠다. 다른 사용방식이 또 있는지는 아직 모르는 수준이다!
@Schema()
export class ChatMessage extends Document {
@Prop({ required: true })
client_id: string;
@Prop({ required: false })
message?: string;
@Prop({ required: true })
sender_id: number;
@Prop({ required: true })
sender_email: string;
@Prop({ required: true })
sender_username: string;
@Prop({ required: true })
sender_profile_img: string;
@Prop({ required: true })
room_id: string;
@Prop({ default: Date.now })
timestamp?: Date;
@Prop({ required: false })
file_name?: string;
@Prop({ required: false })
file_path?: string;
}
export const ChatMessageSchema = SchemaFactory.createForClass(ChatMessage);
Prop 데코레이터는 클래스 필드를 MongoDB Document의 필드로 매핑해주는 역할을 한다.
필드의 유효성이나 옵션을 지정해줄수 있다.
내가 사용한 required, default 말고도 unique 따위도 있다.
@Prop({ type: [String] }) 이런식으로 사용할 수 있다.
이렇게 작성된 스키마를 기반으로 모델을 생성해서 데이터를 처리한다.
그리고 Repository처럼
이렇게 생성자에 넣어주고
요런식으로 써주었다.
이런식으로 CRUD를 간편히 쓸 수 있는 장점이 있는 것 같다.
'BackEnd' 카테고리의 다른 글
| nestJS 실시간 채팅 앱 - [9] logging (winston) (0) | 2024.12.09 |
|---|---|
| 서버 모니터링 (feat. prometheus, grafana) (0) | 2024.12.08 |
| 웹소켓 연결 관리 (NestJS) (3) | 2024.11.28 |
| Proxy (프록시) (0) | 2024.11.06 |
| 자료구조와 자료형 (6) | 2024.10.09 |