🔖 강의 범위: #6.15~19
지난 시간에 db 를 설치, 연결, 데이터 형식 세팅까지 해주었다. 이제 진짜 db와 소통하는 crud 기능을 설치해줄 차례이다.
비디오를 업로드하는 페이지를 만들면서 어떤식으로 CRUD 를 설정할 수 있는지 알아볼 것이다.
그럼 각 기능을 쪼개서 먼저 C(create) 기능부터 만들어보자.
그리고 이어서 R(read) 기능을 통해 만들어진 데이터가 잘 불러와지는지 확인해볼 것이다.
비디오를 업로드하는 페이지를 만들며 새로운 데이터를 데이터베이스에 만들고 읽어오는 작업을 해보자..
Mongoose 스키마는 Mongoose 모델을 구성하기 위한 객체로 생각할 수 있습니다.
https://mongoosejs.com/docs/schematypes.html
몽구스의 모든 것은 스키마로 시작합니다. 각 스키마는 MongoDB 컬렉션에 매핑되고 해당 컬렉션 내 문서의 모양을 정의합니다.
https://mongoosejs.com/docs/guide.html
1) upload template
2) controller 에서 getUpload, postUpload
3) router 에서 videos/upload 라우팅 해주고 get, post 각각 기능 추가해줌
Video model 에 작성한 형식대로 form 은 데이터가 오기를 기대할 것이다.
upload form 이 있는 upload template 으로 돌아가서 input name 에 데이터 형식에 작성했던 키값들을 적어주자.
이제 컨트롤러로 돌아와 클라쪽에서 들어온 정보들을 어떻게 다룰지 보자.
//view
const videoSchema = new mongoose.Schema({
title: String,
description: String,
createdAt: Date,
hashtags: [String],
meta: {
views: Number,
rating: Number,
},
});
//controller
export const postUpload = (req, res) => {
const { title, description, hashtags } = req.body;
const video = new Video ({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(",").map(word => `#${word}`),
meta: {
views: 0,
rating: 0,
}
});
return res.redirect(`/videos/${id}`);
}
❗️ default 속성
- default 속성 설정시 이 때 속성에 함수가 있다면 () 는 빼고 해줘야 한다.
Date.now() (x)
Date.now (o)- default 속성 설정시 컨트롤러에 굳이 언급해줄 필요 없다. 알아서 디폴트값으로 생성해주니까.
- default 속성 외에 mongoose.Schema 에 적용할 수 있는 다양한 속성들은 공식 홈페이지에서 안내해준다.
1)
await 생성된데이터변수명.save()
🌟 ! 주의: 잊지말자. 데베 다룰 때는 await 걸어서 기다려줘야 한다.
만들 때 new Model 대신 Model.create() 을 써주면 .save() 기능을 포함하고 있는 매서드이기 때문에 .save() 를 따로 써줄 필요가 없다.
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
const video = new Video ({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(",").map(word => `#${word}`),
meta: {
views: 0,
rating: 0,
}
});
await 생성된데이터변수명.save()
return res.redirect(`/videos/${id}`);
}
와
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
await Video.create ({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(",").map(word => `#${word}`),
meta: {
views: 0,
rating: 0,
}
});
return res.redirect(`/videos/${id}`);
}
은 같다.
try/catch 구문으로 에러 잡고, 에러메세지 있을 시 view 에도 띄어주기
//controller
export const postUpload = async (req, res) => {
const { title, description, hashtags } = req.body;
try {
const video = new Video ({
title,
description,
hashtags: hashtags.split(",").map(word => `#${word}`),
});
await video.save();
return res.redirect(`/`);
} catch (error) {
console.log(error);
return res.render("upload", {pageTitle: "Upload Video", errorMessage: error._message});
}
}
// upload template
extends base
include mixins/videoMixin
block contents
h1 Welcome to Wetube!
a(href="/videos/upload") Upload Videos →
each video in videos
+videoMixin(video)
else
li Sorry nothing found.
postUpload 과정을 마치고 마지막에 res.redirect("/") 을 설정해 줌으로써 form 에서 정보 전송이 끝나면 홈 화면으로 돌아가도록 해주었다. 그리고 홈 화면에는 home template 이 db 에서 데이터를 불러와 띄우도록 해두었다. 홈화면에 가보자: 데이터를 잘 불러오는 것을 확인할 수 있다.
// videoController / home
export const home = async (req, res) => {
try {
const videos = await Video.find({});
return res.render("home", { pageTitle: "Home", videos })
} catch(error) {
console.log("server error", error)
}
}
불러와진 데이터 타이틀을 클릭하면 watch template 을 띄어 데이터에 관한 상세 내용을 읽을 수 있도록 설정해보자.
//video router
videoRouter.get("/:id([0-9a-f]{24})", watch);
! 정규식 해석: 0부터 9까지, a부터 f까지 문자와 숫자의 배열이며 24개의 문자열이다
//video controller
export const watch = async (req, res) => {
const { id } = req.params;
const video = await Video.findById(id);
return res.render("watch", { pageTitle: video.title, video });
}
! Video.findById(id) 라는 몽구스의 기능 하나를 더 배웠다.
//watch template
block contents
div
p=video.description
small=video.createdAt
a(href=`${video.id}/edit`) Edit Video →
이렇게 생성한 데이터를 잘 불러와지는지도 잘 확인할 수 있었다.
if 조건문을 이용해 404 템플릿(만들어라)을 띄운다.
export const watch = 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("watch", { pageTitle: video.title, video });
}
The req. body object allows you to access data in a string or JSON object from the client side => 클라이언트 사이드, 즉 웹페이지의 form 에서 요청(req)한 데이터들을 볼 수 있게 해준다는 말. 여기에는 input 에 적은 값(키는 input name), 요청한 웹사이트의 params 등이 해당된다.
mongoose.Model 에서 default 설정해주기
db 에 show dbs -> use "내 db" -> show collections -> 내 데이터들 모음집이 나온다.
참고로, 이름이 Video 가 아니라 videos 로 뜨는 이유는, 몽구스가 알아서 제일 첫번쨰는 소문자로 + 끝에 s 를 붙이기 때문이다.
몽구스 매서드 중 다루지 않은 핵심 내용은 .excu 이다. .excu 는 excute(실행하다) 의 약자로 promise 를 따로 걸지 않아도 해당 매서드를 건 statement 에 await 을 걸어준다. 그런 게 있다, 정도로만 이해하고 넘어가자.