학교 공부를 복습할 겸 적는 것이기에 내용이 부족할 수 있습니다.
부족한 것은 상관 없으나, 잘못된 부분이 발견된다면 지적해주시면 감사하겠습니다.
Mongoose란?
Mongoose는 Node.js의 MongoDB용으로 널리 사용되는 ODM(Object Document Mapper) 라이브러리입니다. Mongoose 는 애플리케이션 데이터를 모델링하기 위한 간단한 스키마 기반 솔루션을 제공하며MongoDB 데이터베이스의 문서를 Node.js 프로그램의 개체로 변환하여 데이터 작업을 더 쉽게 만듭니다.
몽구스의 주요 기능
- 문서 매핑
- Mongoose는 MongoDB의 문서를 프로그램의 JavaScript 개체에 매핑합니다. 이를 통해 일반 JavaScript 개체로 작업하는 것처럼 데이터와 상호 작용할 수 있습니다.
- 스키마
- Mongoose에서는 각 컬렉션에 대한 스키마를 정의합니다. 스키마는 각 컬렉션 내 문서의 모양을 정의하는 구조입니다.
- CRUD 작업
- Mongoose는 데이터베이스에서 문서를 생성, 읽기, 업데이트 및 삭제하는 방법을 제공하여 기본 MongoDB 작업을 보다 편리하고 개발자 친화적인 API로 추상화합니다.
- 미들웨어
- 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();
몽구스 모델
- 정의:
- Mongoose의 모델은 스키마 정의에서 컴파일된 생성자입니다.
- 모델 인스턴스 - 문서:
- Mongoose 모델의 인스턴스를 문서라고 합니다.
- 책임:
- 모델은 MongoDB 데이터베이스에서 문서를 생성하고 읽는 역할을 담당합니다. CRUD작업을 위한 인터페이스를 제공하고 정의된 스키마와 일치하는 데이터베이스와의 상호 작용을 허용합니다.
- 특징:
- 몽구스 모델에는 다음과 같은 여러 기능이 제공됩니다.
- 유형 캐스팅: 스키마에 정의된 대로 데이터를 적절한 유형으로 자동 변환합니다.
- 유효성 검사: 데이터를 데이터베이스에 저장하기 전에 스키마에 미리 정의된 유효성 검사 규칙을 기준으로 데이터를 확인하여 데이터 무결성을 보장합니다.
- 쿼리 작성: 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 문서에 포함시키는 과정을 설명하고 있습니다.