2023 - 06 - 17 MongoDB, Mongoose, 몽구스, Schema 스키마, model, populate, Queries 쿼리

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

Mongoose는 Node.js와 MongoDB를 연결해주는 ODM이다.
**ODM(Object Document Mapping) : 객체와 문서를 1대1로 매칭하는 역할
MongoDB의 ODM은 다양하지만 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라는 개념이 존재한다. 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 사용하기
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 아이디 비밀번호 설정
일명령 프롬프트에서 mongod라고 입력한다.
에러가 발생하거나 없다고 뜨시면, 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});