🔖 강의 범위: 6.20~24
지난 시간에는 mongoose.Schema, mongoose.Model, mongoose.find, mongoose.findById 등의 다양한 몽구스의 매서드를 이용해 데이터를 생성하고 서버에 저장하며, 다시 저장한 데이터를 불러오는 CRUD 의 C,R 부분을 공부해보았다. 이 과정에서 callback 함수와 promise 구문에 대해서도 알게 되었다.
watch 페이지를 만들 C,R 기능 만드는 법을 공부했으니,
edit 페이지를 만들며 U(update) 기능 넣는 법을 배워보자.
미들웨어(pre또는 post훅이라고도 불림)는 비동기 함수를 실행하는 동안 제어가 전달되는 함수입니다.
몽구스는 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
Pre
주의❗️) pre안에 콜백함수로 화살표 함수 쓰게 되면 this의 대상이 달라지기 때문에 function(){}으로 써야합니다.
pre("save", async () => {}); (X)
모델에 static 함수를 추가할 수도 있습니다.
스키마에서 컴파일된 모델에 정적 "class" 메서드를 추가합니다.
Static 사용하는 두 가지 방법
// Assign a function to the "statics" object of our animalSchema
animalSchema.statics.findByName = function(name) {
return this.find({ name: new RegExp(name, 'i') });
};
// Or, equivalently, you can call `animalSchema.static()`.
animalSchema.static('findByBreed', function(breed) { return this.find({ breed }); });
https://mongoosejs.com/docs/guide.html#statics
// controllers/ videoController.js
export const getEdit = async (req, res) => {
const { id } = req.params; // const id = req.params.id; 의 es6 버전.
const video = await Video.findById(id);
if (!video) {
return res.render("404", { pageTitle : "404, Not Found"});
}
return res.render("edit", { pageTitle : `Edit ${video.title}`, video });
}
두 가지 방법이 있다:
1) 직접 데이터베이스에서 저장된 값과 req.body 에 전송된 값을 불러와 일일이 수정하는 방법
2) .findByIdAndUpadte( id, { 수정할거 : 수정사항 } ) 몽구스 메서드를 이용하는 방법 🌟
// videoController.js
export const postEdit = async (req, res) => {
const { id } = req.params;
const { title, description, hashtags } = req.body;
const video = await Video.findById(id);
if (!video) {
return res.render("404", { pageTitle: "Video not found." });
}
video.title = title;
video.description = description;
video.hashtags = hashtags
.split(",")
.map((word) => (word.startsWith("#") ? word : `#${word}`));
await video.save();
return res.redirect(`/videos/${id}`);
};
// videoController.js
export const postEdit = async (req, res) => {
const { id } = req.params;
const { title, description, hashtags } = req.body;
const video = await Video.findById(id);
if (!video) {
return res.render("404", { pageTitle: "Video not found." });
}
await Video.findByIdAndUpdate(id, {
title,
description,
hashtags: hashtags
.split(",")
.map((word) => (word.startsWith("#") ? word : `#${word}`)),
});
return res.redirect(`/videos/${id}`);
};
2가지 방법이 있다.
1) 몽구스의 middleware(미들웨어) 기능 사용
2) 몽구스의 static(정적인) 기능 사용
미들웨어는 데이터모델을 만든 파일에서 생성해주며, 반드시 데이터모델을 생성하기 "전"에 생성 해야 한다.
// models/Video.js
videoSchema.pre("save", async function () {
해당 기능(여기선 save 기능) 을 사용하기 "전"(pre) 구현하고 싶은 기능 적기
});
// 예시
videoSchema.pre('save', async function () {
this.hashtags = this.hashtags[0]
.split(",")
.map((word) => (word.startsWith("#") ? word : `#${word}`));
});
.static 은 데이터 형식 내에 자주 사용할 함수를 직접 정의할 수 도 하고 사용을 간단하게 해준다. (즉, 내가 원하는 함수를 직접 커스터마이징 하는 거랄까...)
기본적으로 그냥 함수 선언하고 import, export 해서 쓰는 원리이다. 단, 굳이 import, export 를 해주지 않아도 선언한 함수 이름만으로 사용 가능하다는 점에서 훨씬 유용하다.
사용법
Schema이름.static("함수명", function (인자) { 함수 커스터마이징 } );
// 예: static 선언 in Video.js
const videoSchema = new mongoose.Schema({
title: { type: String, required: true, uppercase: true },
description: { type: String, required: true },
createdAt: { type: Date, required:true , default: Date.now },
hashtags: [{type:String, trim:true}],
meta: {
views: { type: Number, default: 0 },
rating: { type: Number, default: 0 },
},
});
videoSchema.static("formatHashtags", function (hashtags) {
return hashtags
.split(",")
.map((word) => word.startsWith("#") ? word : `#${word}`)
});
const Video = mongoose.model("Video", videoSchema);
export default Video;
// static 사용 in videoController.js
await Video.create ({
title,
description,
hashtags: Video.formatHashtags(hashtags),
});