웹 시스템 개발 #Mongoose

학교 공부를 복습할 겸 적는 것이기에 내용이 부족할 수 있습니다.

 

부족한 것은 상관 없으나, 잘못된 부분이 발견된다면 지적해주시면 감사하겠습니다.

 


Mongoose란?

Mongoose는 Node.js의 MongoDB용으로 널리 사용되는 ODM(Object Document Mapper) 라이브러리입니다. Mongoose 는 애플리케이션 데이터를 모델링하기 위한 간단한 스키마 기반 솔루션을 제공하며MongoDB 데이터베이스의 문서를 Node.js 프로그램의 개체로 변환하여 데이터 작업을 더 쉽게 만듭니다.

 

몽구스의 주요 기능

  1. 문서 매핑
    • Mongoose는 MongoDB의 문서를 프로그램의 JavaScript 개체에 매핑합니다. 이를 통해 일반 JavaScript 개체로 작업하는 것처럼 데이터와 상호 작용할 수 있습니다.
  2. 스키마
    • Mongoose에서는 각 컬렉션에 대한 스키마를 정의합니다. 스키마는 각 컬렉션 내 문서의 모양을 정의하는 구조입니다.
  3. CRUD 작업
    • Mongoose는 데이터베이스에서 문서를 생성, 읽기, 업데이트 및 삭제하는 방법을 제공하여 기본 MongoDB 작업을 보다 편리하고 개발자 친화적인 API로 추상화합니다.
  4. 미들웨어
    • Mongoose를 사용하면 데이터베이스 작업의 다양한 단계(예: 문서를 저장하기 전)에서 실행할 수 있는 미들웨어 기능을 정의할 수 있습니다.

 

객체 관계형 매핑(ORM)과 비교

  • Mongoose는 MongoDB(NoSQL 데이터베이스)용으로 설계된 ODM인 반면, Sequelize, Hibernate, MyBatis와 같은 ORM 도구는 관계형 데이터베이스(MySQL, PostgreSQL 등)용으로 설계되었습니다.

 

MongoDB vs Mongoose

특징/ 측면  MongoDB  Mongoose
스키마 스키마 X 스키마 O
검증 내장된 유효성 검사 X 자동적인 유효성 검사 O
쿼리 인터페이스 MongoDB 쿼리와 직접 상호 작용 함수 체이닝을 제공
성능 데이터베이스와의 직접적인 상호 작용으로 인해 더 빠름 추가 추상화 계층으로 인해 약간 느림

 

 

스키마 및 모델 생성의 예

import mongoose from 'mongoose'; 
const { Schema } = mongoose;

// Define the schema
const blogSchema = new Schema({
  title: String,  // String is shorthand for {type: String}
  author: String, // “author” is the path of this field
  body: String,
  comments: [{ body: String, date: Date }], // Array of objects with body and date
  date: { type: Date, default: Date.now },  // Default value for date
  hidden: Boolean,
  meta: {       // Nested object with votes and favs
    votes: Number,
    favs: Number
  }
});

// Create a model from the schema
const Blog = mongoose.model('Blog', blogSchema);

// Instantiate a document from the model
const doc = new Blog();

 

 

몽구스 모델

  1. 정의:
    • Mongoose의 모델은 스키마 정의에서 컴파일된 생성자입니다. 
  2. 모델 인스턴스 - 문서:
    • Mongoose 모델의 인스턴스를 문서라고 합니다. 
  3. 책임:
    • 모델은 MongoDB 데이터베이스에서 문서를 생성하고 읽는 역할을 담당합니다. CRUD작업을 위한 인터페이스를 제공하고 정의된 스키마와 일치하는 데이터베이스와의 상호 작용을 허용합니다.
  4. 특징:
    • 몽구스 모델에는 다음과 같은 여러 기능이 제공됩니다.
      • 유형 캐스팅: 스키마에 정의된 대로 데이터를 적절한 유형으로 자동 변환합니다.
      • 유효성 검사: 데이터를 데이터베이스에 저장하기 전에 스키마에 미리 정의된 유효성 검사 규칙을 기준으로 데이터를 확인하여 데이터 무결성을 보장합니다.
      • 쿼리 작성: MongoDB 데이터베이스에 대한 복잡한 쿼리 생성을 용이하게 합니다.

 

몽구스에서 모델 만들기

기본 모델 생성:

  • 모델을 생성하려면 mongoose.model() 함수를 사용합니다.
  • 첫 번째 인수는 모델이 속한 컬렉션의 이름입니다. Mongoose는 이 이름을 사용하여 데이터베이스에서 해당 컬렉션을 찾습니다.
  • 관례에 따라 Mongoose는 컬렉션 이름으로 모델 이름의 복수형 소문자 버전을 자동으로 찾습니다. 예를 들어 'Tank'라는 모델을 생성하면 Mongoose는 기본적으로 이 모델을 데이터베이스의 'tanks' 컬렉션과 연결합니다.
const schema = new mongoose.Schema({ name: String, size: String }); 
const Tank = mongoose.model('Tank', schema);

const small = new Tank({ size: 'small' });
await small.save(); 
// or
await Tank.create({ size: 'small' });
// or, for inserting large batches of documents 
await Tank.insertMany([{ size: 'small' }]);

 

 

사용자 정의 연결 사용:

  • 사용자 지정 연결로 작업하는 경우 해당 연결의 'model()' 함수를 사용하여 모델을 만들어야 합니다.
const connection = mongoose.createConnection('mongodb://127.0.0.1:27017/test');
const Tank = connection.model('Tank', schema);

 

 

Mongoose 모델을 사용한 CRUD 작업

Querying

  • 문서 검색: 데이터베이스에서 문서를 가져오기 위해 Mongoose 모델은 여러 가지 방법을 제공합니다.
    • find(): 쿼리와 일치하는 모든 문서를 검색합니다.
    • findById(): _id로 단일 문서를 검색합니다.
    • findOne(): 쿼리와 일치하는 단일 문서를 검색합니다.
    • where(): 쿼리 조건을 연결하는 방법을 제공합니다.
    • 예: await Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec();
      • 이 쿼리는 'size'가 'small'이고 'createdDate'가 'oneYearAgo'보다 큰 모든 'Tank' 문서를 가져옵니다.

Deleting

  • 문서 제거:
    • deleteMany(): 주어진 쿼리와 일치하는 모든 문서를 삭제합니다.
    • deleteOne(): 주어진 쿼리와 일치하는 첫 번째 문서를 삭제합니다.
    • 예: await Tank.deleteOne({ size: 'large' });
      • 이 명령은 size가 'large'인 단일 Tank 문서를 삭제합니다.

Updating

  • 문서 수정: 데이터베이스의 문서를 업데이트하기 위해 모델은 업데이트 방법을 제공합니다.
    • updateOne(): 지정된 필터와 일치하는 첫 번째 문서를 업데이트합니다.
    • updateMany(): 지정된 필터와 일치하는 모든 문서를 업데이트합니다.
    • 예: await Tank.updateOne({ size: 'large' }, { name: 'T-90' });
      • 이 명령은 'size'가 'large'인 단일 'Tank' 문서를 업데이트하고 'name'을 'T-90'으로 설정합니다.

 

Connection

  • Mongoose의 역할: Mongoose는 Express 애플리케이션 내에서 애플리케이션과 데이터베이스 사이의 중개자 역할을 합니다.
    • 통신 구조: MongoDB는 오직 Mongoose와만 통신하며, Mongoose는 Node와 Express와 통신합니다. 클라이언트 측 애플리케이션은 MongoDB나 Mongoose와 직접 통신하지 않고, 오로지 Express 애플리케이션과만 통신합니다.
  • 버퍼링: 모델을 즉시 사용할 수 있게 하는 버퍼링 기능이 있지만 문제가 있습니다: Mongoose는 데이터베이스에 연결하지 않고 모델을 사용해도 기본적으로는 오류를 발생시키지 않습니다. 
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/test’);  // return Promise resolves to this if succeeded

 

 

Connection: Error Handling

mongoose.connect('mongodb://127.0.0.1:27017/test')
.catch(error => handleError(error));
// 또는:
try {
  await mongoose.connect('mongodb://127.0.0.1:27017/test'); 
} catch (error) {
  handleError(error); 
}
mongoose.connection.on('error', err => { 
  logError(err);
});

 

Validation

Mongoose는 여러 내장 유효성 검사기를 가지고 있습니다.

  • 모든 스키마 타입은 필수(required) 유효성 검사기를 내장하고 있습니다. 이 필수 유효성 검사기는 SchemaType의 checkRequired() 함수를 사용하여 값이 필수 조건을 만족하는지 확인합니다.
  • 숫자에는 최소값(min)과 최대값(max) 유효성 검사기가 있습니다.
  • 문자열에는 열거형(enum), 일치(match), 최소 길이(minLength), 최대 길이(maxLength) 유효성 검사기가 있습니다.
javascriptCopy code
const bookSchema = new mongoose.Schema({
  title: { type: String, required: true },
  publisher: String,
  date: { type: Date, default: Date.now },
  onSale: Boolean,
  price: Number
});

 

Validation Example 

async function saveBook() {
  const book = new Book({ 
    publisher: "Oreilly Media", 
    onSale: false,
    price: 59.99, 
  });
  try {
    const result = await book.save(); 
    console.log(result);
  } catch (err) {
    console.log(err.message) 
  }
}

saveGame();

<결과>
sangyoonoh $node validation.js
책 유효성 검사 실패: title: `title` 경로가 필요합니다.

 

 

Populate

  • populate() 함수는 다른 컬렉션의 문서를 참조하게 해줍니다.

참조 저장하기

const author = new Person({
  _id: new mongoose.Types.ObjectId(),
  name: 'Ian Fleming',
  age: 50
});
await author.save();
const story1 = new Story({
  title: 'Casino Royale',
  author: author._id  // Person의 _id를 할당
});
await story1.save();

 

Population 사용 예시

const story = await Story
  .findOne({ title: 'Casino Royale' })
  .populate('author')
  .exec();
// "저자는 Ian Fleming입니다" 출력
console.log('The author is %s', story.author.name);

 

 

이 코드는 Mongoose에서 populate 메소드를 사용하여 다른 컬렉션의 문서들을 참조하는 방법을 보여줍니다. 예제에서는 Person 컬렉션의 author 문서를 Story 컬렉션의 story1 문서와 연결하여, 쿼리를 수행할 때 author의 정보를 story 문서에 포함시키는 과정을 설명하고 있습니다.