본문 바로가기
Development

MongoDB? Mongoose로 편하게 사용하자!

by 차암새 2020. 10. 9.

안녕하세요 :D

 

휴몬랩 초보개발자 참새입니다 :>

 

NoSQL 데이터베이스로 분류되는 MongoDB는 가장 유명한! NoSQL데이터베이스 시스템입니다.

 

그렇다면  Mongoose는 무엇일까요?

출처 velog

Mongoose는 Node.js와 MongoDB를 연결해주는 ODM입니다!

**ODM(Object Document Mapping) : 객체와 문서를 1대1로 매칭하는 역할

MongoDB의 ODM은 다양하지만 Mongoose가 가장 유명합니다.

 

자! 그럼 지금부터 Mongoose를 파해쳐보겠습니다.

 

패키지 설치


npm install mongoose --save
yarn add mongoose

위와 같이 노드 패키지 매니저 npm 혹은 yarn을 통해 설치할 수 있습니다!!

 

MongoDB 연결하기


1) require을 이용하는 방법

const mongoose = require('mongoose');
mongoose.connect("mongodb://lodcallhost/<db이름>", 
{useNewUrlParser: true});

2) import를 이용하는 방법

import mongoose from 'mongoose';

mongoose.connect('mongodb://localhost/<db이름>',
{useNewUrlParser: true});

*** 두 가지 방식 중 개발 방향에 맞는 코드를 사용하시면 됩니다! ***

 

우선 mongoose 모듈을 require(혹은 import)해줍니다. 그 이후 connect 메소드를 통해 MongoDB에 연결해야 합니다.

connect 메소드의 인자로는 mongdodb url(기본적으로는 localhost를 사용합니다.) 과 useNewUrlParser와 같이 error발생하지 않도록 다른 인자들을 객체 형식으로 선언합니다.

 

만약 본인만의 mongoDB 서버가 있으시다면 url인자에 'mongodb://username:password@host:port/database'  를 보내주시면 됩니다!

 

 

Schema 생성하기


Mongoose는 Schema라는 개념이 존재합니다. SQL에 익숙하신 개발자분들은 사실 처음 NoSQL을 사용하면 많이 어려우실 수 있습니다. 'table'이라는 개념이 없기 때문이죠. MongoDB의 경우 Document에 데이터를 아무거나 막 넣어도 에러가 발생하지 않습니다. 이는 양날의 검과 같은데, 데이터를 막 넣을 수 있기에 편리하지만 반대로 불필요한 데이터 같은 데이터도 다 들어가며, 어떤 경우엔 원하는 자료형과 맞지 않는 데이터가 들어갈 수도 있는 문제가 있습니다.

 

그래서.....!!

Mongoose는 Schema를 도입한 것입니다. 스키마는 SQL의 table과 비슷한 개념이라고 생각하시면 됩니다. 데이터를 넣을 때 schema에서 선언한 틀에 맞게 데이터를 넣을 수 있도록 해줍니다. 

 

그럼 이제 스키마를 만들어 보도록 하겠습니다.

import mongoose from 'mongoose';

const imageSchema = new mongoose.Schema({
  width : Number,
  height : Number,
});

const developersSchema = new mongoose.Schema({
  name : {type : String, required: true},
  age : {type : Number, required: true},
  image : imageSchema,
  nickname : String,
  language : String,
  friends : [String],
});

 

간단한....? 스키마를 만들어 보았습니다. 

스키마는 위와 같이 mongoose를 import 한 뒤, new mongoose.Schema({});를 통해 생성할 수 있습니다.

 

필드를 하나씩 파헤쳐 보겠습니다!

name은 String타입이며, required : true를 통해 꼭 필요한 값으로 지정을 했습니다.

age는 Number타입이며, 이 또한 required : true를 통해 필요한 값으로 지정을 했습니다.

 

image필드는 다른 필드와 조금 다르게 선언되었습니다. imageSchema라고 지정이 되어있죠?

이는 image필드는 imageSchema라는 또 다른 스키마를 타입으로 가집니다.

풀어서 보면

image : { width : Number,

            height : Number,

           } 

정도로 볼 수 있습니다!! 

 

nickname은 String타입으로 선언되었습니다. (language도 동일!)

friends는 String타입의 배열로 선언되었습니다.

 

자, 이렇게 스키마를 만든 다음엔 무엇을 해주어야 할까요?

스키마를 데이터베이스 서버로 쏙 넣어주어야 합니다.

import mongoose from 'mongoose';

const imageSchema = new mongoose.Schema({
  width : Number,
  height : Number,
});

const developersSchema = new mongoose.Schema({
  name : {type : String, required: true},
  age : {type : Number, required: true},
  image : imageSchema,
  nickname : String,
  language : String,
  friends : [String],
});

const model = mongoose.model('Developer',developerSchema);

데이터베이스 서버로 넣어주기 위해서는 구현해놓은 schema를 model 메소드를 통해 객체로 만들어주어야 합니다.

따라서 model이라는 객체를 생성한 뒤, 그 객체에 스키마 model을 넣어주었습니다.

 

이후 각자 원하는 서버에 올리시면 됩니다!!

 

Populate 사용하기


다음으로는 Mongoose의 기능 중 하나인 populate에 대해서 알아보도록 할까요?

 

 MongoDB 스키마를 만들다 보면, 필드 내에 다른 다큐먼트의 ObjectID를 쓰는 경우 존재합니다.

 

예시는 다음과 같습니다.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const personSchema = Schema({
  _id: Schema.Types.ObjectId,
  name: String,
  age: Number,
  stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

const storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'Person' },
  title: String,
  fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});
출처 : https://mongoosejs.com/docs/populate.html

위의 _id와 stories를 보면 타입으로 Schema.Types.ObjectId가 지정되어있습니다.

MongoDB에서는 데이터가 차곡차곡 쌓일 때, 그 데이터 하나하나를 document라고 합니다.

_id와 stories는 그 document를 가리키는 타입인 것입니다.

 

그럼 실제로 데이터를 조회하면 어떻게 될까요?

 { _id: {$oid : 5a23c1b5d52a003c98e13f1c},
  name: 'CharmSae',
  age: 16, 
  stories : {$oid :5a23c1b5d52a003c98e13f1b},
  }

이런 형식으로 데이터가 조회됩니다. _id와 stories에 document id값이 저장이 되어있습니다.

Populate는 간단하게 말해서 이런 id값을 펼쳐서 보여주는 기능이라고 생각하시면 편합니다.

 

사용과 그에 따른 결과는 다음과 같습니다.

Person.findOne({ name: 'charmsae' }).populate('stories').exec((err, data) => {
  console.log(data);
}); 


 { _id: {$oid :5a23c1b5d52a003c98e13f1c},
  name: 'CharmSae',
  age: 16, 
  stories : {
      author : {$oid :5a23c1b5d52a003c98e13f1d},
      title : 'HueMoneLabStory'
      fans : {$oid :5a23c1b5d52a003c98e13f1d},
  	},
  }

위의 결과랑은 다르게 stories에 어떠한 document가 출력이 되었죠?

이렇게 populate를 활용하면 Schema.Types.ObjectId가 참조하는 다른 document를 조회할 수 있습니다!

 

하지만 populate를 남발하는 것은 좋지 않습니다. populate는 $oid값을 조회한 뒤 자바스크립트에서 합쳐주는 것이지 DB 자체에서는 합쳐지지 않기에 성능이 좋은 편은 아니기 때문입니다.

 

 

Queries


다음 데이터를 조회하는 방식인 Query에 대해서 알아보도록 하겠습니다.

Mongoose에는 다양한 Query가 존재하는데 그중 대표적인 것들만 알아보도록 하겠습니다.

더 자세한 Query는 mongoose 공식 사이트를 참고해주세요 https://mongoosejs.com/docs/queries.html

findOne()

const query = Person.findOne({name : 'charmsae'});
//Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나'불러옵니다.

find()

const query = Person.find({name : 'charmsae'});
//Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '모두' 불러옵니다.

 

deleteOne()

const query = Person.deleteOne({name : 'charmsae'});
//Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나' 삭제합니다.

deleteMany()

const query = Person.deleteMany({name : 'charmsae'});
//Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '모두' 삭제합니다.

이때, One이 들어간 쿼리문은 가장 처음 조회되는 document를 불러옵니다.

다음은 유용하게 사용되는 또 다른 쿼리문을 알아보겠습니다.

 

sort()

const query = Person.find({name : 'charmsae'}).sort(age : -1);
//Person이라는 컬렉션 안에서 name이 charmsae인 모든 document를 age순으로 정렬합니다.
//이때, age : 1이면 오름차순, age : -1이면 내림차순으로 정렬합니다.

 

select()

const query = Person.findeOne({name : 'charmsae'}).select('age');
//Person이라는 컬렉션 안에서 name이 charmsae인 documents를 '하나' 조회한 뒤,
// age 필드만 가져옵니다.

 

이 외에도 많은 쿼리문들이 있지만 상황에 따라 성능이 다르기 때문에 위에 첨부한 공식 사이트를 참고하여 상황에 맞는 쿼리문을 사용하는 것을 추천드립니다!!

 

 

MongoDB, Mongoose 아이디 비밀번호 설정


MongDB를 사용하다 보면, 귀찮다고 생각해서 아이디와 비밀번호를 설정해놓지 않는데, 다양한 이유가 있지만 대표적으로 외부 접속을 위해서라도 설정을 해놓아야 합니다. (랜섬웨어가 발생하여 타격을 입은 사례도 있습니다 ㅠㅠ)

 

일단 명령 프롬프트에서 mongod라고 쳐줍니다! 에러가 발생하거나 없다고 뜨시면, mongodb를 먼저 설치하시면 됩니다!! 

***mongoDB설치는 공식 사이트에 들어가서 설치하시면 됩니다!!

 

위와 같이 뜨면 성공!

 

그 뒤에는 명령 프롬포트를 하나 더 띄운 뒤 mongo라고 쳐줍니다.

위와 같이 뜨시면 이제 준비가 된 겁니다!!

그런 뒤에 아래와 같이 입력합니다.

use admin
db.createUser({ user: '이름', pwd: '비밀번호', roles: [{role : "userAdminAnyDatabase"}] })

그런 뒤, 다시 mongoose파일로 가서 

const mongoose = require('mongoose');
mongoose.connect("mongodb://lodcallhost/<db이름>", 
{useNewUrlParser: true});

와 같이 작성한 코드를 다음과 같이 수정해줍니다.

const mongoose = require('mongoose');
mongoose.connect('mongodb://아이디:비밀번호@호스트:포트/dbname'), 
{useNewUrlParser: true});

이렇게 하면 모든 과정이 끝납니다!!

 

 

마치면서...


mongoose는 mongoDB를 쉽게, 편리하게 사용할 수 있는 ODM입니다. mongoose를 활용하여 , NoSQL의 장점을 적극적으로 끌어올려, 데이터베이스를 다루셨으면 좋겠습니다.

 

다음엔 더 좋은 글로 찾아오겠습니다.

참새였습니다. :D

댓글