영상저장이나 업데이트 전에 메일유효성검사, 비속어확인, 해시태그 처리등 object가 저장되기전에 무언가를 하고싶을 때
-->mongoose에서도 express와 같은 개념인 .middleware 사용
express에서 middleware
request를 중간에 가로채서 뭔가를하고 이어서 진행하는것
무엇을 하고 next콜한다음 request를 계속 처리
예) morgan middleware
mongoose에서 middleware
save, update 하기 전, 후로 middleware를 적용하거나 function 실행할 수있다.
express middleware처럼 흐름을 방해하지않아 그냥 무엇을하고 흐름을 이어감
몽구스는 document middleware, model middleware, aggregate middleware, query middleware 4가지 미들웨어가 있습니다.
https://mongoosejs.com/docs/middleware.html#middleware
model middleware가 지원하는 기능
document middleware함수에서 this는 현재 document를 참조합니다. https://mongoosejs.com/docs/middleware.html#types-of-middleware
사용법
shema.pre('save', async function() {
await doStuff();
await doMoreStuff();
})
model > Videos.js에서 작업
!!middleware는 무조건 model이 생성되기 전에 만들어야 함
videoSchema.pre('save', aysnc function(){
console.log("we are going to save", this); //여기서 this 키워드는 저장되는 비디오 다큐먼트를 뜻함
this.title ="i'm middle ware" // 수정 할 수있음
})
--> 우리가 할거 video.create 에 있는 hashtags
await Video.create({
title,
description, hashtags: hashtags hashtags, .split(",") .map((word) => (word.startsWith("#") ? word : `#${word}`)),
});
몽구스미들웨어에서는
videoSchema.pre('save', aysnc function(){
console.log(this)// 당연히 해시태그 처리 안됨, 몽구스가 자동으로 배열로 바꿔주는데 분리되어있지않고 배열의 첫번째 element로 지정함 예) ['for,real,now,mongo'] 첫번 째 요소
따라서 배열의 첫번째 요소로 저장된 것을 나눠주고 동작
videoSchema.pre('save', async function () {
this.hashtags = this.hashtags[0]
.split(",").
map((word) => (word.startsWith("#") ? word : `#${word}`));
});
})
db.videos.remove({}) 로 데이터베이스 삭제 후 테스트
db.videos.find()
pre middleware를 save 이벤트에 동작한 결과임
이제 업데이트를 위한 함수를 만들어야함
-----------------------------------------------------------------------------------------------------------------------------------
findByIdAndUpdate를 위한 pre middleware는 없다.
findOneAndUpdate를 호출 findOneAndUpdate는 미들웨어있음
문제는 save hook을 호출 하진 않고
- Pre and post save() hooks are not executed on update(), findOneAndUpdate(), etc.
업데이트하려는 문서에 접근 할 수 없다.
- You cannot access the document being updated in pre('updateOne') or pre('findOneAndUpdate') query middleware.
videoSchema.pre('save', async function () {
this.hashtags = this.hashtags[0] //save는 업데이트 접근가능
.split(",").
map((word) => (word.startsWith("#") ? word : `#${word}`));
});
우리는 ,presave, preupdate둘다 사용하고 싶은데,,
일단 pre.save코드를 지우고
이전 상황으로 돌아온다.
videoController안에 video.create안에 해시태그 처리방법 기재한 상태로 --> hashtags처리할때 마다 복붙 해야함
2.Video.js에 옵션만들기
export const formatHashtags = (hashtags) =>
hashtags.split(",").map((word) => (word.startsWith("#") ? word : `#${word}`))
익스포트하고
videoController 내에
await Video.create({
title,
description,
hashtags: formatHashtags,
사용하고 , 임포트하기 (사용하면 자동으로 윗줄에 임포트 됨 그래도 확인하기)
import Video, { formatHashtags } from "../models/Video";
export const postEdit = async (req, res) => {
const { id } = req.params;
const { title, description, hashtags } = req.body;
const video = await Video.exist({ _id: id });
if (!video) {
return res.render("404", { pageTitle: "Video not found" })
}
await Video.findByIdAndUpdate(id, {
title,
description,
hashtags: formatHashtags(hashtags),
})
--------------------------------------------------------------------------------------------------------------------------------.
3.다른 방법: static
Video.findById, Video.exist 처럼
Video function을 커스터마이징
Video만 import하면 됨 함수를 임폴트할 필요없음
Schemaname.static('만들고자하는 static이름', function(){});
Video.js에
videoSchema.static('formatHashtags', function (hashtags) => hashtags.split(",").map((word) => (word.startsWith("#") ? word : `#${word}`)));
controller에
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
try {
await Video.create({
title,
description,
hashtags: Video.formatHashtags(hashtags),
});
1. findByIdAndUpdate()에서는 save 훅업이 발생하지 않음 => 다른 방법을 알아보자
2. Video.js에 function을 만들어서 관리하기 => 이것도 괜찮음 근데 다른것도 알아보자
3. static을 사용하면 import 없이도 Model.function()형태로 사용이 가능함 => super cool