[엘리스 SW트랙 4기] 6주차 - Day 30: MongoDB

랸나·2023년 4월 7일
0
그래도 이해한 부분: 라우팅, 스키마, 몽고디비 연결 등
어려워하는 부분 : 에러처리 + 요청받은 데이터를 파악한 뒤, 정제해서 다시 응답으로 내보내는 것(문법 필요, 데이터 타입 파악 필요, 어떻게 내보낼것인지 구조화 필요)

흐름은 이해했으나, 그 흐름속에서 구체적으로 데이터 정제와 출력을 어떻게 하는건지 어려워한다. 아마 문법이 좀 모자라고 기본 개념이 모자라서 막히는 것 같다. 

그리고 에러처리가 어렵다. throw err 등의 형식이 진짜 익숙치 않다. 사실 2주전?까지만 해도 에러처리를 왜 해야하는지 전혀 감도 못잡았으니까..
(에러가 안나야 좋은거 아님? 에러를 왜 캐치하지? 이러고 있었다..)

에러처리는 모두 비동기를 위한 큰그림이었던것.. 
비동기로 치면 네트워크 문제로 데이터의 요청 수신 모두 실패할 가능성이 있으니, 그때를 위한 에러처리였던 것..! 이라고 현재는 어렴풋이 이해한다.

부족한 부분을 알았으니.. 파고들 수 있겠다.. 그치만 어렵다..ㅠ 아무리 봐도 익숙치 않다 데이터 정제는.. 

01. MongoDB와 Mongoose

MongoDB

MongoDB란?

  • 대표적인 NoSQL, Document DB
  • Hyumongous에서 따온 말로, 엄청나게 큰 DB라는 의미
    => 대용량 데이터를 처리하기 좋게 만들어짐

NoSQL vs RDB

RDBNoSQL
Relational DatabaseNoSQL
관계형 데이터베이스구조화된 질의어를 사용하지 않는 데이터베이스
자료들의 관계를 주요하게 다룸자료 간의 관계에 초점을 두지 않음
SQL질의어를 사용하기 위해 데이터를 구조화 해야함데이터를 구조화하지 않고, 유연하게 저장함

NoSQL을 사용하는 이유

  • SQL을 사용하기 위해서는 데이터를 구조화하는 것이 필수 (DDL)
    -> 스키마에 정의된 데이터가 아니면 저장할 수 없는 제약이 따름

  • 사전 작업 없이 데이터베이스를 사용할 수 있음.
    -> 데이터베이스 작업에 크게 관여하지 않고 프로젝트를 빠르게 진행할 수 있음.

  • NoSQL 예시 (사진 출처 : 엘리스 SW 엔지니어 트랙)

  • RDB 예시 (사진 출처 : 엘리스 SW 엔지니어 트랙)

NoSQL과 Document DB

  • NoSQL은 다양한 종류가 있지만, 대표적으로 자료를 Document(문서)로 저장하는 Document DB가 일반적.
  • 이 외에 key0value, Graph, large collection 등의 NoSQL DB가 존재.

MongoDB 기본 개념

  • Database : 하나 이상의 Collection을 가질 수 있는 저장소. SQL의 데이터베이스와 유사한 개념
  • Collection : 하나 이상의 Document가 저장되는 공간. SQL에서의 table과 유사. 하지만 Collection이 Document의 구조를 정의하지 않음.
  • Document : MongoDB에 저장되는 자료. SQL에서 row와 유사하지만 구조 제약 없이 유연하게 저장 가능. JSON과 유사한 BSON(Binary JSON)을 사용하여 다양한 자료형을 지원.
    • ObjectID각 document에는 유일한 키 값, SQL의 Primary Key와 유사한 하나씩 증가하는 값이 아닌 document를 생성할 때 자동으로 생성되는 값이 있음.
    • timestamp + random value + auto increament

MongoDB 사용 방법

  • 직접 설치 : 직접 모든 DB 관련 설정 해야함. Sharding이나 Replication 등의 작업이 필요할 때 운영지식과 노하우가 요구됨.
  • 클라우드 설치 : 모든 DB설정을 웹에서 가능. 사용량에 따라 비용 발생, 512mb까지는 평생 무료 사용 가능.
  • MongoDB Compass : DB를 시각화하여 관리. MySQL Workbench와 유사

Mongoose ODM

Mongoose ODM

  • Object Data Modeling
  • MongoDB의 Collection에 집중하여 관리하도록 도와주는 패키지
  • Collection을 모델화하여, 관련 기능들을 쉽게 사용할 수 있도록 도와줌

연결관리

  • MongoDB의 기본 Node.js드라이버는 연결 상태를 관리하기 어려움
  • Mongoose를 사용하면 간단하게 데이터베이스와 연결 관리 가능

스키마 관리

  • 데이터 형식을 미리 정의해야 코드 작성과 프로젝트 관리에 유용함.
  • Mongoose는 Code-Level에서 스키마를 정의하고 관리할 수 있게 해줌.

Populate

  • MongoDB는 기본적으로 Join 제공하지 않음.
  • 원래는 Join과 유사한 기능을 가진 aggregate라는 복잡한 쿼리를 사용해야하지만, Mongoose 덕분에 populate를 사용하여 간단하게 구현 가능!

Mongoose ODM 사용 방법

사용 순서

1. 스키마 정의

const { Schema } = require("mongoose");

//Document 스키마를 코드 레벨에서 관리할 수 있도록 스키마 작성
const PostSchema = new Schema({
	title:  String,
  	content: String,
}, {
	timestamps : true, //생성, 수정 시간을 자동으로 기록해줌
});

module.exports = PostSchema;

2. 모델 만들기

const mongoose = require('mongoose');

const PostSchema = require('./schemas/board');

exports.Post = mongoose.model('Post', PostSchema);
// 작성된 스키마를 mongoose에서 사용할 수 있는 모델로 만들어야함. 
// 모델의 이름을 지정하여 Populate 등에서 해당 이름으로 모델 호출 할 수 있음. 

3. 데이터베이스 연결

const mongoose = require('mongoose');
const { Post } = require('./models);
mongoose.connet('mongodb://localhost:27017/myapp');

// Post 바로 사용 가능
// Mongoose는 자동으로 연결 관리를 해줘서 직접 연결상태를 체크하지 않아도 모델 사용시 연결 상태를 확인하여 비동기적으로 사용 가능할 때 작업을 실행함. 

4. 모델 사용

CRUD함수명
Createcreate
READfind, findById, findOne
UPDATEupdateOne, updateMany, findByIdAndUpdate, findOneAndUpdate
DELETEdeleteOne, deleteMany, findbyIdAndDelete, findOneAndDelete
  • CREATE
const { Post } = require('./modles');

async function main(){
	const created = await Post.create({
    	title: 'first title',
        content: 'second title',
    }); //단일 Document 생성
  
    const multpleCreated = awiat Post.create([
    	item1,
        item2
    ]); // 복수 Document 생성
  
}
  • Find
const { Post } = require('./modles');

async function main(){
	const listPost = await Post.find(query); //어레이 반환
    const onePost = await Post.findOne(query); //하나의 다큐먼트 반환 
    const postById = await Post.findById(id);
  	// qeury를 사용하여 검색하거나 findById를 사용하면 ObjectID로 Documnet 검색 가능
};

** 쿼리란? => BSON형식으로, SQL의 where와 유사한 조건절 사용하는 것. 
MongoDB의 기본 문법 그대로 mongoose에서도 사용 가능
  • 쿼리 예시
Person.find({
	name : "hanna", // { key: value}로 exact match
  	age: {
    	$lt: 20, //less than
      	$gte: 10, //greater than equal
    },
  	languages: {
    	$in: ['ko', 'en'], // 다중 값으로 검색. 전달된 배열에 데이터가 하나라도 있다면, 그 데이터가 리턴됨.
    },  //위에 세개까지는 모두 and조건으로 묶임. 아래는 or 로 묶임 
    $or: [ // 다중 조건 검색, 
      { status: 'ACTIVE'},
      { isFresh: true},
    ],
});

// mongoose는 쿼리값으로 배열이 주어지면 자동으로 $in쿼리를 생성하줌

쿼리들은 https://www.mongodb.com/docs/manual/reference/operator/query/ 에서 참고하자.

  • UPDATE
async function main(){
	const updateResult = await Post.updateOne(query, {
      ..
    }); //쿼리 결과 반환 (수정된 개수 몇개고.. 어쩌구..)
	const updateResults = await Post.updateMany(query, {
      ... //쿼리 결과 반환 (수정된 개수 몇개고.. 어쩌구..)
    }); 
    const postById = await Post.findByIdAndUpdate(id, {
      ...
    }); //몽구스에서는 $set operator를 사용하여 Document를 통째로 변경하지 않음(몽고디비에서는 통째로 갈아치움)
  	const onePost = await Post.findOneAndUpdate(query, {
      ...
    });//find~함수들은 검색된 Document를 업데이트를 반영하여 반환해줌 
}
  • DELETE
async function main(){
	const deleteResult = await Post.deleteOne(query);
    const deleteResults = await Post.findOneAndDelete(query);
  	// 삭제 결과를 리턴
  
    const onePost = await Post.findOneAndDelete(query);
  	const postById = awiat Post.findByIdAndDelete(query);
	// find된 다큐먼트들을 반환함.
}
  • populate
const Post = new Schema({
	..
  user: {
  	type: Schema.Types.ObjectId,
  	ref: 'User'
  },
  comments: [{
 	type: Schema.Types.ObjectId,
    refL 'comment',
  }],
});

const post = awiat Post
	.find().populate(['user', 'commnets']);

//post.user.name, post.comments[0].content

Expressjs + Mongoose ODM

Mongoose ODM 위치 정하기

  • 일반적으로 models 디레겉리에 Schema와 Model을 같이 위치
  • app 객체는 어플리케이션 시작을 의미하는 부분이므로 해당 부분에 데이터베이스 연결을 명시하는 mongoose.connect를 위치
  • 출처 : 엘리스 SW 엔지니어 트랙

Mongoose ODM 커넥션 이벤트

  • Express.js 어플리케이션은 종료되지 않고 동작하기 때문에 계속해서 데이터베이스가 정상적으로 동작하는지를 파악하기 위해 동작 중에 발생하는 데이터베이스 연결 관련 이벤트에 대한 처리를 하는 것이 좋음.
mongoose.connect('----');

mongoose.connection.on('connected', () => {
}); //연결완료 이벤트

mongoose.connection.on('disconnected', () => {
}); //연결이 끊김

mongoose.connection.on('reconnected',() => {
}); // 재연결 완료

mongoose.connection.on('reconnectFailed, () => {
}); // 재연결 시도 횟수 초과

Sequelize ORM (참고)

ODM

  • Object-Realational Mapping
  • MySAL, PostgreSQL 등의 RDBMS를 이용하는 간단한 방법
  • ODM이 단순히 모델에 집중하여 관리하는 것에 반해 ORM은 테이블의 관계과 쿼리 등의 기능을 더욱 단순화 하는 용도로 주로 사용
profile
백엔드개발자

0개의 댓글