본문 바로가기
개발/node

Mongoose 개념 및 사용법 정리

by amkorousagi 2021. 3. 19.

mongoose

MongoDB는 전통적인 관계형 DB인 Mysql, Mssql, Oracle 등 과 달리, 비 관계형 DB이며, json과 같은 document 기반의 구조를 가진다.

관계형 DB에 비해 MongoDB는 데이터 저장 및 검색에 대해 덜 제한적이다.

 

이런 MongoDB를 더 편리하게 사용할 수 있는 Mongoose라는 npm 패키지를 소개하고자 한다.

MongoDB와 Mongoose 기본 개념(구조)

MongoDB와 Mongoose 개념도

우선, 가장 작은 단위부터 보자.

 

MongoDB

Document

document는 mongoDB의 가장 작은 데이터 저장 단위이다.

 

이 document는 그냥 하나의 json object라고 보면 된다.

key:value를 저장하고 있는 text라는 의미이다. 

 

Collection

Collection은 여러 Document의 모임이다.

 

이 collection의 이름은 일반적으로 그 collection이 가지고 있는 document의 단수형을 복수형으로 바꾼 것으로 한다.

비슷한(또는 같은) 형태의 document들을 모아둔 것이다.

 

물론 이런 관례를 무시하고 전혀 다른 형태의 document를 같은 collection에 쑤셔 넣을 수 있다.

하지만, 그건 좋은 생각이 아닐 것이다.

 

Database

Database는 여러 collection의 모임이다.

모임이라기보다는 소속되어 있는 장소라고 생각하는 게 편하다.

 

관리자는 여러 개의 database를 만들고 관리할 수 있다.

 

Mongoose

Model

mongoose의 model과 mongoDB의 document는,

이전 포스팅에서 말한 DOM과 HTML document의 관계성과 비슷하다. 

 

mongoDB에서 document를 단순한 "text"이다.

이런 text를 구조화하고 생성 및 수정 등 DB에 접근하게 도와주는 여러 interface를 제공하는 것이,

바로 model이다.

 

model은 두 가지로 구성된다.

shema와 methods이다.

 

schema는 해당 document에 대한 구조의 definition(정의)이다.

정적으로 멤버들을 선언한다고 생각하면 된다.

 

methods는 schema에서 정의한 구조(key-value)대로 document를 create 하거나,

만든 document에 해당하는 collection에서 document를 검색하는 등의 DB에 access 하는 interface를 제공한다.

 

아래는 예제 코드이다.

const personSchema = new mongoose.Schema({ name: 'string', age: 'string' });
const Person = mongoose.model('Person', schema);

 

위 코드를 보면 한 가지 의문이 들 것이다.

"collection에 대한 언급이 없네?"

 

그렇다.

위에서는 어느 collection에 model로 생성한 document를 저장할지 정의하고 있지 않다.

그러면 어떻게 하는가?

 

mongoose는 자동으로 단수형 모델 이름의 복수형을 collection의 이름(lowercase 됨)으로 설정한다.

(물론 model의 세 번째 인자로 자신의 특정하여 collection이름을 설정할 수 있다.)

Mongoose automatically looks for the plural, lowercased version of your model name.
-mongoose 공식 문서-

Collection

mongoose에서 collection에 대해 건드릴 수 있는 건, 위에서 언급했듯이

model 호출할 때 세 번째 인자로 collection이름을 지정하는 것뿐이다.

 

Database

mongoose에서 database에 대해 건드릴 수 있는 건,

처음 connect를 호출할 때 database에 대한 url(또는 ip와 port)를 넘겨주는 것뿐이다.

mongoose
  .connect(config.url, {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false,
    useCreateIndex: true,
  })
  .then(() => {
    logger.info("connected to MongoDB")
  })
  .catch((err) => {
    logger.error("error connecting to MongoDB:", err.message)
  })

 

JSON화

noteSchema.set('toJSON', {
  transform: (document, returnedObject) => {
    returnedObject.id = returnedObject._id.toString()
    delete returnedObject._id
    delete returnedObject.__v
  }
})

 

CRUD

create : new Model({new properties}).save()

read : Model.find({}) or Model.findById(id)

update: Model.findByIdAndUpdate(id, {new properties}, {options})

delete: Model.findbyIdAndDelete(id)

느낀 점 및 더 말하고 싶은 점

역시 단순함을 추구하는 NoSQL이다. RDBMS에 비해 정말 Data Definition Langueage와 Data Management Lanuage를 작성하기 편해졌다.

 

또 두 collection 간의 관계도 object id를 저장하든지 해서 마음대로 서로가 서로를 참조(둘 다 Foreign Key를 가지도록) 만들어도 아무도(특히 DBMS가) 머라 안 한다. 중복 참조라고 혼내지 않는다는 말이다.

 

하지만, 만능은 아닌 게 Nosql자체가 join쿼리를 지원하지 않기 때문에 mongoose의 populate라는 method를 써서 두 collection을 join 하더라도 그 join 하는 도중에 일어나는 해당 collection의 update에 대해서는 join 된 결과에서는 보장하지 못한다.

 

보통 그냥 덜 보여도 reload 하면 되는 가벼운 일이나, read보다 write가 많을 때 사용한다고 한다. 

 

참고한 사이트:(mongoose 공식 문서)

 

Mongoose ODM v5.12.1

Let's face it, writing MongoDB validation, casting and business logic boilerplate is a drag. That's why we wrote Mongoose. const mongoose = require('mongoose'); mongoose.connect('mongodb://localhost:27017/test', {useNewUrlParser: true, useUnifiedTopology:

mongoosejs.com

댓글