20230630TIL

뿌링클 치즈맛·2023년 7월 2일
0

Elice AI트랙 8기

목록 보기
26/28

Mongo DB

대표적인 Not only Structured Query Language, Document DataBase
이름의 mongo는 humongous를 줄인 표현이라고 한다.엄청 큰 DB 라는 뜻이다!

Structured Query Language
SQL. 데이터베이스 시스템에서 자료를 처리하는 용도로 사용되는 구조적 데이터 질의 언어.

Not only Structured Query Language
구조화된 질의어를 사용하지 않는 데이터베이스. RDB를 사용하지 않는 것이 아니라, 여러 유형의 DB를 사용한다.
자료 간의 관계에 초점을 두지 않는다. 데이터를 구조화하지 않고, 유연하게 저장한다.

Relational DataBase
관계형 데이터베이스. DB 중 가장 많이 쓰이고 있다.
데이터를 로우(Row: 행, 줄)와 컬럼(Column: 열, 칸)이라는 일종의 표 형태로 저장한다. 데이터의 종속성은 관계(Relation)으로 표현한다.SQL 질의어를 사용하기 위해 데이터를 구조화해야 한다.

NoSQL을 사용하는 이유?

1.SQL을 사용하기 위해서는 구조적인 데이터를 사용해야 하는데, 스키마(DB의 구조와 제약 조건에 관한 전반적인 명세를 정의한 메타데이터의 집합)에 정의된 데이터가 아니면 저장할 수 없는 제약이 따른다.
2.NoSQL을 사용하면 사전작업(구조화) 없이 데이터베이스를 사용할 수 있다.
→ 데이터베이스 작업에 크게 관여하지 않고 프로젝트를 빠르게 진행할 수 있음

MongoDB의 구조

Document가 모여서 Collection이 되고, Collection이 모여 DataBase를 구성한다.

Document는 JSON과 유사한 BSON구조로 되어있다. RDBMS의 row와 유사하지만, 구조의 제약 없이 유연하게 저장할 수 있다. Document 기반의 DB는 RDB와 달리 자유롭게 데이터 구조를 잡을 수 있다.
ObjectID는 각 Document의 유일한 키 값, RDBMS의 primary key에 해당한다. Document를 생성할 때 자동으로 생성되는 (따로 지정하지 않으면) 난수값이다.
Collection은 Document의 집합이다. RDBMS의 Table에 해당한다.
DataBase는 Collection의 집합이고, 이는 RDBMS에서도 동일하다.
몽구스

Mongoose ODM

Mongoose Object Data Modeling
Mongoose는 MongoDB의 Collection에 집중하여 관리하도록 도와주는 패키지이다. Collection을 모델화하여, 관련 기능들을 쉽게 사용할 수 있도록 도와준다.
ODM을 Object Document Mapping로 해석하는 경우에는, Document를 자바스크립트의 객체로 바꾸어주는 역할을 하는 것이 된다.

Mongoose ODM 사용 이유

  1. 연결 관리(DB와의 연결 상태를 간단하게 관리할 수 있다.)
  2. 스키마 관리(스키마를 정의하지 않고 데이터를 사용할 수 있는 것이 NoSQL의 장점이지만, 데이터의 형식을 미리 지정해주는 것이 코드 작성과 프로젝트 관리에 유용하다.)
  3. Populate (RDBMS의 Join과 유사한 기능. 복잡한 쿼리 구현 없이 populate를 통해 사용할 수 있다.)

Mongoose 사용

  1. 스키마 정의
//models/schema/board.js
const { Schema } = require('mongoose');
const PostSchema = new Schema({
	title: String, 
	content: String,
}, {
	timestamps: true,
});
module.exports = PostSchema;

mongoose에서 Schema를 불러와 PostSchema 객체에 새로운 스키마(title:문자열,content:문자열)을 저장한다. timestamps는 생성,수정 시간을 자동으로 기록해주는 옵션이다. PostSchema를 모듈로 export 해준다.

  1. 모델 생성
//modles/index.js
const mongoose = require('mongoose');
const PostSchema = require('./schemas/board');
exports.Post = mongoose.model('Post', PostSchema);

작성된 스키마를 mongoose에서 사용할 수 있는 모델로 만들어야 하기 때문에, index.js에서 PostSchema를 불러온다. 'Post'라는 이름으로 PostSchema를 전달해 모델을 만든다. 만들어진 모델은 exports.Post에서 Post라는 이름으로 export한다.

3.DB 연결

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

connect 함수를 이용하여 간단하게 데이터베이스에 연결할 수 있다.
mongoose는 자동으로 연결을 관리해 주어 직접 연결 상태를 체크하지 않아도 모델 사용 시 연결 상태를 확인하여 사용이 가능할 때 작업을 실행한다. DB연결 시간, DB연결시에 발생하는 오류 등을 체크하고 연결이 정상적으로 되었을 때 이후의 작업을 실행한다.

Mongoose를 통한 CRUD 구현

CREATE
const { Post } = require('./models');
async function main() {
	const created = await Post.create({ //1
		title: 'first title',
		content: 'second title',
});
const multpleCreated = await Post.create([//2
  item1, 
  item2
]);
}

1) Document Object를 통해 단일 Document를 생성한다. Post 모델에 create를 사용해 Document Object를 통해 title로는 first title, content로 second title을 설정했다.
2) Document Object의 Array도 전달이 가능하다. 2번에 create의 매개변수로 item1,item2라는 배열을 전달했고, 배열이 전달될 때는 복수의 Document가 생성된다.
create는 생성된 Document를 반환해준다!

FIND
const { Post } = require('./models');
async function main() {
	const listPost = await Post.find(query);
	const onePost = await Post.findOne(query);
	const postById = await Post.findById(id);
}

find와 관련된 함수(find,findOne,findById)를 사용해 Document를 검색한다.find,findOne에는 매개변수로 쿼리가 들어가고, findById에는 매개변수로 id가 들어간다.find는 리스트로 배열 형식의 데이터를 받아오고,findOne과 findById로 각각 하나의 Document를 받아온다.

Query

MongoDB에도 SQL의 where와 유사한 조건절 사용 가능
MongoDB의 query는 BSON 형식으로, 기본 문법 그대로 mongoose에서도 사용 가능

Person.find({
  name: 'kyubum',
  age: {
    $lt: 20,
    $gte: 10,
  },
  languages: {
    $in: ['ko', 'en'],
  },
  $or: [
    { status: 'ACTIVE' }, 
    { isFresh: true },
  ],
});

Object 형태 { key: value } 로 전달되어 exact match.
$lt, $lte, $gt, $gte 를 사용하여 range query 작성 가능

$lt : less than

$lte : less than equal

$gt : greater than

$gte : greater than equal

$in : ['ko','en'] 배열로 전달받은 값 중 하나라도 일치한다면 그 값을 찾아 전달한다.

$or: [{ status: 'ACTIVE' },{ isFresh: true },] 배열로 다중 조건을 전달받고, 둘 중 하나가 일치하는 것을 찾는다.

UPDATE
async function main() {
  const updateResult = await Post.updateOne(query, {
    });
  const updateResults = await Post.updateMany(query, {
  });
  const postById = await Post.findByIdAndUpdate(id, {
  });
  const onePost = await Post.findOneAndUpdate(query, {
  });
}

update 관련 함수를 사용하여 Document를 수정한다. findByIdAndUpdate는 id를 전달받고 findOneAndUpdate는 query를 전달받아 Document를 업데이트를 반영하여 반환한다. mongoose의 update는 기본적으로 $set operator 를 사용하여, Document를 통째로 변경하지 않고 일치하는 값만 변경한다.

DELETE
async function main() {
  const deleteResult = await Post.deleteOne(query);
  const deleteResults = await Post.deleteMany(query);
  const onePost = await Post.findOneAndDelete(query);
  const postById = await Post.findByIdAndDelete(query);
}

delete 함수를 사용해 Document를 삭제한다. find~함수를 통해 검색한 Document를 반환후 삭제한다.

Populate
const Post = new Schema({
  user: { 
    type: Schema.Types.ObjectId, 
    ref: 'User' 
  },
  comments: [{
    type: Schema.Types.ObjectId,
    ref: 'Comment',
  }],
});
const post = await Post.find().populate(['user', 'comments']);

Post 스키마 안에 user와 comments가 들어있다. user와 comment의 type은 Schema의 Type의 ObjectId라는 ObjectId타입(다른 Object의 id값)으로 선언되어있고,ref로 각각 User와 Comment모델을 참조한다. user는 단일 객체, comments는 배열로 선언되어 있다. 단일 객체뿐만 아니라 배열로도 참조할 수 있다.

RDMBS의 JOIN과 유사한 기능이다. JOIN은 두개 이상의 데이터베이스나 테이블을 연결해서 데이터를 검색하는 연산으로, 한 쇼핑몰에서 노트북을 구매한 고객 A가 있다면,구매 내역 테이블과 배송정보 테이블에 모두 포함된 A의 아이디라는 하나의 칼럼을 기준으로 마치 하나의 테이블처럼 검색을 할 수 있게 해주는 쿼리 문법이다.
Populate는 스키마에서 ref로 지정된 테이블에서 정보를 얻어온 다음에, 그 정보를 ObjectId가 있던 자리에 붙여준다. user는 User에서 ObejctId를 찾아 user 스키마의 타입으로 넣어준다.

Document 안에 Document를 담지 않고,ObjectID를 가지고 reference하여 사용할 수 있는 방법을 제공한다.
Document에는 reference되는 ObjectID를 담고, 사용할 때 populate하여 하위 Document처럼 사용한다.
참고 링크

profile
뿌링클 치즈맛

0개의 댓글