티스토리 뷰

개발공부/🟩 Node.js

[NodeJS] Mongoose ODM

2022. 7. 31. 20:34

 

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

 

 

 Mongoose ODM 

 

▶ Mongoose ODM 이란?

 

MongDB의 Collection에 집중하여 관리하도록 도와주는 패키지

 

→  MongoDB의 Collection을 JavaScript의 model로써 만들어놓고

이 model을 통해 MongoDB의 데이터들에 쉽게 접근하고 관련 기능들을 쉽게 사용할 수 있도록 도와줌

 

*  ODM (Object Data Modeling)  :  Data를 Object로 Model화하여 관리

 

 

 

 

▶ Mongoose를 사용하는 이유

 

1)  연결관리

:  MongoDB에서 기본 제공하는 Node.js 드라이버는 연결상태를 관리하기가 어려움

→  Mongoose를 사용하면 간단하게 데이터배이스와의 연결상태를 관리 가능

 

2)  스키마 관리

:  스키마를 정의하지 않고 데이터를 사용할 수 있는 것이 NoSQL의 장점이지만 데이터 형식을 미리 정의하는 것이 코드작성과 프로젝트 관리에 유용

→  Mongoose는 Code-Level에서 스키마를 정의하고 관리 가능

 

3)  Populate

:  MongoDB는 기본적으로 Join을 제공하지 않아서 Join과 유사한 기능을 사용하기 위해 aggregate라는 복잡한 쿼리 필요

→  Mongoose는 populate를 사용하여 Join 기능을 간단하게 구현 가능

 

 

*  Populate 란?

:  스키마 선언 시 Document 안에 Document를 담지 않고 ObjectID를 가지고 reference하여 사용할 수 있는 방법을 제공

→  Document에는 reference되는 ObjectID를 담고 사용할 때 populate하여 하위 Document처럼 사용 가능

const Post = new Schema({
    ...,
    user: {		// 단일 객체 reference 가능
        type: Schema.Types.ObjectId, 
        ref: 'User'		// User모델 선언 시 전달했던 모델의 이름
    },
    comments: [{	// array로도 reference 가능
        type: Schema.Types.ObjectId,
        ref: 'Comment',		// Comment모델 선언 시 전달했던 모델의 이름
    }],
});


// ObjectId 사용
const post = await Post.find().populate(['user', 'comments']);	
// post.user.name, post.comments[0].content 처럼 사용 가능

 

 

 

 

 

▶ Mongoose 사용하기

 

1)  스키마 정의

 

-  Collection에 저장될 Document의 스키마를 Code-Level에서 관리할 수 있도록 Schema 작성

-  다양한 형식을 미리 지정하여 생성, 수정 작업 시 데이터 형식을 체크해주는 기능 제공

-  timestamps 옵션을 사용하면 생성, 수정 시간을 자동으로 기록

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

const PostSchema = new Schema({
    title: String, 
    content: String,
}, {
    timestamps: true,
});

module.exports = PostSchema;

 

 

2)  모델 만들기

 

-  작성된 스키마를 mongoose에서 사용할 수 있는 모델로 생성

-  모델의 이름을 지정하여 Populate 등에서 해당 이름으로 모델 호출

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

exports.Post = mongoose.model('Post', PostSchema);

 

 

3)  데이터베이스 연결

 

-  connect() 를 이용하여 데이터베이스에 연결

-  mongoose는 connect 함수를 사용했을 때 자동으로 연결을 관리해줌

→  직접 연결 상태를 체크하지 않아도 모델 사용 시 연결 상태를 확인하여 사용이 가능할 때 비동기적으로 작업을 실행

const mongoose = require('mongoose');
const { Post } = require('./models');

mongoose.connect('mongodb://localhost:27017/myapp');

// Post 바로 사용 가능

 

 

4)  모델 사용

 

-  작성 된 모델을 이용하여 CRUD 수행

CRUD 함수명
CREATE create
READ find,  findById,  findOne
UPDATE updateOne,  updateMany,  findByIdAndUpdate,  findOneAndUpdate
DELETE deleteOne,  deleteMany,  findByIdAndDelete,  findOneAndDelete

 

 

CREATE

:  create() 함수를 사용하여 Document 생성

 

'Document Object(단일 Document 생성)'나 'Document Object의 Array(복수 Document 생성)' 전달 가능

→ create는 생성된 Document를 반환

const { Post } = require('./models');

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

 

 

 

 

FIND (READ)

:  find 관련 함수를 사용하여 Document 검색

 

query를 사용하여 검색하거나 findById를 사용하면 ObjectID로 Document를 검색 가능

const { Post } = require('./models');

async function main() {
    const listPost = await Post.find(query);	// 인자 : query / 반환 : array
    const onePost = await Post.findOne(query);	// 인자 : query / 반환 : 하나의 document
    const postById = await Post.findById(id);	// 인자 : objectID / 반환 : 하나의 document
}

 

* query 란?

-  MongoDB에도 SQL의 where와 유사한 조건절 사용 가능

-  MongoDB의 query는 BSON 형식으로, 기본 문법 그대로 mongoose에서도 사용 가능

 

≫ query 관련 MongoDB 메뉴얼

 

Query Documents — MongoDB Manual

Docs Home → MongoDB Manual➤ Use the Select your language drop-down menu in the upper-right to set the language of the following examples.This operation corresponds to the following SQL statement:The following example selects from the inventory collecti

www.mongodb.com

≫ MongoDB query operator

 

Query and Projection Operators — MongoDB Manual

Docs Home → MongoDB ManualFor details on specific operator, including syntax and examples, click on the specific operator to go to its reference page.For comparison of different BSON type values, see the specified BSON comparison order.NameDescriptionMat

www.mongodb.com

 

* 자주 사용되는 query

-  { key: value } 로 exact match

-  $lt, $lte, $gt, $gte 를 사용하여 range query 작성 가능

-  $in 을 사용하여 다중 값으로 검색

-  $or 를 사용하여 다중 조건으로 검색

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



// 참고 : Mongoose는 쿼리 값으로 배열이 주어지면 자동으로 $in 쿼리를 생성해 줌
Person.find({ name: ['elice', 'bob'] });
// { name: { $in: ['elice', 'bob'] } }

 

 

 

 

UPDATE

:  update 관련 함수를 사용하여 Document 수정

 

find~ 함수들은 검색된 Document에 업데이트를 반영하여 반환

mongoose의 update는 기본적으로 $set operator를 사용하여 Document를 통째로 변경하지 않음

(MongoDB의 update 기능은 해당되는 Document가 통째로 변경됨)

async function main() {
    const updateResult = await Post.updateOne(query, {    // update 결과 리턴
    	...
    });
    const updateResults = await Post.updateMany(query, {    // update 결과 리턴
    	...
    });
    const postById = await Post.findByIdAndUpdate(id, {    // 검색된 Document에 update를 반영하여 Document 리턴
    	...
    });
    const onePost = await Post.findOneAndUpdate(query, {    // 검색된 Document에 update를 반영하여 Document 리턴
    	...
    });
}

 

 

 

DELETE

:  delete 관련 함수를 사용하여 Document 삭제

 

find~ 함수들은 검색된 Document를 반환

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);
}

 

 

 

 

 

 

▶ Express.js에서 Mongoose 사용하기

 

Express.js는 프로젝트 구조를 자유롭게 구성할 수 있기 때문에

어느 부분에 Mongoose ODM을 위치시키면 좋을지 적절한 위치를 결정하는 것이 중요

 

-  일반적으로 models 디렉터리에 Schema와 Model을 같이 위치

-  app객체는 어플리케이션 시작을 의미하는 부분이므로 app객체가 선언되는 부분에 데이터베이스 연결을 명시하는 mongoose.connect를 위치

이미지출처 : 엘리스 Node.js와 MongoDB Ⅱ - 01 MongoDB와 Mongoose 강의자료

 

 

 

Mongoose 커넥션 이벤트

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

 

connected  -  연결 완료

disconnected  -  연결 끊김

reconnected  -  재연결 완료

reconnectFailed  -  재연결 시도 횟수 초과

mongoose.connect('----');

mongoose.connection.on("connected", () => {
  console.log("Successfully connected to MongoDB");
})

mongoose.connection.on('disconnected', () => {
	...
});

mongoose.connection.on('reconnected', () => {
	...
});

mongoose.connection.on('reconnectFailed', () => {
	...
});

 

 

 

 

 

 

 

 + 참고)  Sequelize ORM 

 

▶ Sequelize ORM 이란?

 

MySQL, PostgreSQL 등의 RDBMS를 이용하는 간단한 방법

→  ODM이 단순히 모델에 집중하여 관리하는 것에 반해 ORM은 테이블 관계와 쿼리 등의 기능을 더욱 단순화하는 용도로 주로 사용

 

-  Sequelize ORM 을 사용하면 데이터베이스에 직접 DDL을 하지 않고 JavaScript 코드로 테이블 및 관계를 관리할 수 있음

-  또한 RDB의 어려운 점 중 하나인 join을 간단하게 사용할 수 있음

 

* ORM (Object-Relational Mapping)  :  Object와 Relation을 Mapping

 

 

 

1)   DB 연결

-  sequelize도 Mongoose처럼 연결을 관리하는 간단한 방법을 제공

-  mongoose가 MongoDB만 연결이 가능한 데에 반해 sequelize는 MySQL, PostgreSQL, SQLite 등 다양한 RDBMS 에 연결 가능

const sequelize = new Sequelize('database', 'username', 'password', {
    host: 'localhost',
    dialect: 'mysql'
});

 

2)  스키마 작성

-  sequelize는 define을 통해 Schema를 생성

-  mongoose.Schema와 유사하지만 sequelize는 Schema가 DDL도 생성해줌

const User = sequelize.define('User', {
    name: {
        type: DataTypes.STRING(10),
        allowNull: false
    },
    age: {
    	type: DataTypes.Integer,
    }
}, {});

 

 

3)  관계 정의

-  sequelize를 이용하면 테이블 간의 관계를 Code-Level로 관리 가능

-  이를 이용하면 외래키 설정과 제약조건까지 DDL로 자동으로 생성해줌

-  또한 다대다 관계 설정을 통해 relation table도 자동으로 생성해줌

User.hasMany(Post);
Post.belongsTo(User);
Foo.belongsToMany(Bar);
Bar.belongsToMany(Foo);

 

4)  쿼리

-  Operator를 이용해 SQL 쿼리를 코드로 작성 가능

-  스키마의 관계 설정을 한 경우, include를 사용하여 자동으로 join 쿼리 생성 가능

User.findAll({
    where: {
        name: 'elice',
        age: {
            [Op.lt]: 20,
            [Op.gte]: 10,
        }, 
    },
    include: User,
});

 

5)  Synchronization

-  define된 model 데이터를 바탕으로 DDL을 자동으로 실행해줌 

-  직접 데이터베이스에 접속하여 테이블 생성 및 관리를 할 필요가 없음

-  자동으로 생성된 DDL을 따르지 않으면 테이블 관리가 어려워짐

sequelize.sync();

 

 

 

 

 


이 글은 엘리스 AI트랙 5기 강의를 들으며 정리한 내용입니다.

반응형
프로필사진
개발자 삐롱히

프론트엔드 개발자 삐롱히의 개발 & 공부 기록 블로그