전 파트에서 배웠듯이
schema
는 비디오의 형태를 정의 해준다.
video.js
에서 살펴보면
import mongoose from "mongoose";
const videoSchema = new mongoose.Schema({
title: String,
description: String,
createdAt: Date,
hashtags: [{ type: String }],
meta: {
views: Number,
rating: Number,
},
});
const Video = mongoose.model("Video", videoSchema);
export default Video;
보이다시피 영상의 각 구성요소와 데이터 형태를 보여주고 있다.
이걸 이해했다면 사용자가 비디오를 업로드 할때 해당 schema
의 데이터들을 보내줄 수 있다.
물론 생성일이나 meta
데이터는 사용자에게 자동으로 제공해 준다.
비디오를 업로드하는 사람은 title
, description
, hashtags
만 올려주면 된다.
upload
를 위한 view
를 바꿔 준다.
upload.pug
에서
extends base.pug
block content
form(method="POST", action="/videos/upload")
input(name="title", placeholder="Title", requried, type="text")
input(name="Description", placeholder="Description", requried, type="text")
input(name="Hashtags", placeholder="Hashtags, separated by comma.", requried, type="text")
input(type="submit", value="Upload Video")
참고로 모든 input
에는 name
을 부여해야 한다.
이걸로 필요한 구성 요소들은 완성이 되었다. 한번 더 강조 하지만 각기 다른 name
을 꼭 부여해야 한다.
browser
를 새로고침 해주면 필요 요소들이 추가 된걸 알수 있다.
이제 controller
가 form
을 다룰 수 있게 만들어 준다.
여기서 꼭 기억해야 하는 것은 form
에는 URL
이란 action
이 있다.
form(method="POST", action="/videos/upload")
그리고 만약 이 부분을 삭제 한다면 HTML
은 이 URL
또는 form
이 부여해주는 주소로 간다.
이전과 같으니까 코드를 정리해 주도록 한다.
form(method="POST")
그리고 이 시점에서 router
를 어떻게 구성 했는지 되돌아 본다.
videoRouter.js
로 가서 보면
import express from "express";
import { get } from "express/lib/response";
import {
watch,
getEdit,
postEdit,
getUpload,
postUpload,
} from "../controllers/videoController";
const videoRouter = express.Router();
videoRouter.route("/:id(\\d+)").get(watch);
videoRouter.route("/:id(\\d+)/edit").get(getEdit).post(postEdit);
videoRouter.route("/upload").get(getUpload).post(postUpload);
export default videoRouter;
upload
가 있고, template
을 render
하는 getUpload
가 있다.
그리고 지금 다루게 될 postUpload
가 있다.
다시 videoController.js
로 가서 보면
postUpload
는 현재 title
만 다루고 있다. 왜냐하면 이전에 그렇게 구성했기 때문이다.
하지만 이제 description
과 hashtags
가 추가 되었다.
그러니 controller function
에 위 두개를 추가해 준다.
export const postUpload = (req, res) => {
const { title, Description, Hashtags } = req.body;
return res.redirect("/");
};
이걸로 description
과 hashtags
도 추가 되었다.
export const postUpload = (req, res) => {
const { title, Description, Hashtags } = req.body;
console.log(title, Description, Hashtags);
return res.redirect("/");
};
console.log(title, Description, Hashtags);
추가 해줬다. 지금하고 있는 것은 전에 배운 내용에 대한 짧은 복습이다.
form
이 데이터베이스에게 데이터를 전송 해주는걸 볼거다.
해당 정보를 upload
화면을 통해 전송해본다. 새로고침을 한다음 빈 공백에 문자를 넣어주고
upload
를 누르면 redirect
이 된다.
이 동작은 정상적인게 해당 코드가 home
으로 보내지도록 만들었다.
console
에 이 세가지가 출력 되어야 한다.
터미널을 통해 확인해 보면
✅ Server listening on port http://localhost:4000 🚀
✅Connected to DB
GET /videos/upload 304 176.113 ms - -
dsfasf ehfdhdgn sdfhs
POST /videos/upload 302 27.095 ms - 46
GET / 304 64.110 ms - -
순서대로 잘 나오고 있다.
자 이제 비디오를 어떻게 만들어야 할까?
이걸하기 위해 document
를 만들어 줘야한다. document
는 데이터를 가진 비디오라 생각하면 된다.
그리고 document
를 database
에 저장해야 한다. 그럼 일단 document
만드는거 부터 해본다.
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("/");
};
const video = new Video({})
이 코드 안에 video model
의 구성 요소들을 담아준다.
video.js
에서 보면서
const videoSchema = new mongoose.Schema({
title: String,
description: String,
createdAt: Date,
hashtags: [{ type: String }],
meta: {
views: Number,
rating: Number,
},
});
title
,description
,createdAt
,hashtags
,meta
를 추가해 주었다.
createdAt
의 경우 data.now
를 부여해 주는데 data.now
의 값은 다음과 같다.
console
에 data.now()
입력 해보면 나오는 숫자는 1970년1월1일0시0분0초부터 현재까지의 milliseconds
라고 한다.
현재 schema
와 같은 모양으로 document
를 만들었다.
차이점이 있다면 document
는 실제 데이터를 담는 다는 것이다.
title,
description,
이런 단축 코드로 입력 하는게 싫을수도 있는데 사실 이렇게 적는 것과 의미는 똑같다.
title:title<,
description:description,
왼쪽 title
은 schema
의 것이고 오른쪽 title
은 request.body
안의 것을 뜻한다.
hashtags
는 string
으로 구성된 array
인 점을 고려해야 하는데
console
환경에서 위와 관련된 frontend
와backend
의 관련된 몇가지 실험을 할거다.
이에 대한 예제를 보도록 하자.
"hello,food,totally,delis"
사용자가 우리에게 이 정보를 보내줬다고 한다.
이 상황에서 split
라 불리는 function
을 사용해 준다.
"hello,food,totally,delis".split(",")
split
은 string
들을 분리 하는 기능을 가지고 있다.
spliter
또는 separator
가 그 분리의 기분이 되는데 쉼표를 기준으로 해준다.
이 코드는 쉼표를 볼때 마다 string
을 나눠 줄거다.
(4) ["hello","food,""totally","delis"]
결과는 이런식으로 array
를 가지게 된다. 이게 바로 array
를 만드는 방식이다.
이걸 hashtags
에 적용해 줄건데 아주 쉽고 아주 효율적이다.
이게 사용자에게 upload
시 hashtag
를 쉼표로 나누라고 한 이유이다.
다른 방법으로 예제를 보면
"#hello,#hi,#lalala".split(",")
이렇게 입력 하면
(3) ["#hello","#hi","#lalala"]
된다.
string
에 #(해시태그)가 없다면 #(해시태그)가 없는 상태에서 추가하고 싶으면
두가지 function
을 이어서 실행해주면 된다.
"food,movies,music".split(",")
먼저 split
을 해주고
(3) ["food","movies","music"]
그럼 이 상태로 console
에 입력 되어 있고
"food,movies,music".split(",").map(word =>
#${word})
그 다음 map
을 실행 시켜준다.
그리고 모든 단어들 앞에 #(해시태그)을 붙여준다.
(3) ["#food","#movies","#music"]
array
를 만들어 단어별 분리를 시킨 다음 #을 붙여 줄거다.
이게 바로 hashtags
코드를 구성하는 원리가 된다.
먼저
hashtags
의 존재를 확실히 해줘야한다.
하지만 이 부분에서 이미 required
된 상태라 크게 걱정 할 필요는 없을 듯하다.
form
을 믿어 보도록 한다.
hashtags: hashtags.split(",").map((word) => `#${word}`),
그래서 이렇게 입력 하게 되었다. 그리고 보다시피 video object
하나가 완성 되었다.
const video = new Video({
title,
description,
createdAt: Date.now(),
hashtags: hashtags.split(",").map((word) => `#${word}`),
meta: {
views: 0,
rating: 0,
},
이 부분은 실재 하는 데이터와 관련되어 있다. form
에서 전송되는 데이터 말이다.
이걸로 hashtags
가 완성 되었다.
그럼 이제
video
를 한번console.log
해본다.
import Video from "../models/Video";
export const home = async (req, res) => {
const videos = await Video.find({});
return res.render("home", { pageTitle: "Home", videos });
};
export const watch = (req, res) => {
const { id } = req.params;
return res.render("watch", { pageTitle: `Watching` });
};
export const getEdit = (req, res) => {
const { id } = req.params;
return res.render("Edit", { pageTitle: `Editing` });
};
export const postEdit = (req, res) => {
const { id } = req.params;
const { title } = req.body;
return res.redirect(`/videos/${id}`);
};
export const getUpload = (req, res) => {
return res.render("upload", { pageTitle: "Upload Video" });
};
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,
},
});
console.log(video);
return res.redirect("/");
};
console.log(video);
return res.redirect("/");
new video
를 실행 시키게 되는데 이걸 console.log
하고 home
화면으로 넘어간다.
여기서 한가지 의문점이 든다. 방금의 작업이
database
상에 저장이 될까..?
확인해 보도록 한다. 새로고침 해주고 빈칸을 채워 주고 upload
한다.
결과로 보자면 아직 database
상에 아무것도 존재하지 않는다.
하지만 console
에서 보여주는 결과 값은 상당히 잘 나와 있다.
GET /videos/upload 200 16.410 ms - 754
{
title: 'Video 1',
description: 'Best JS',
createdAt: 2022-04-10T08:36:39.589Z,
hashtags: [ '#hi', '#how', '#are', '#you' ],
meta: { views: 0, rating: 0 },
_id: new ObjectId("625297179ddafe0e40ee48d7")
}
POST /videos/upload 302 12.340 ms - 46
GET / 304 23.606 ms - -
이 형식은 설계한 video
랑 똑같다. hashtahs
는 string
으로 된 array
이고
title
있고 description
있고 date
도 있고 meta
도 있어 그리고 마지막으로
생성된 고유 id
도 있다. mongoose
가 id
를 부여 해준거다.
왜냐하면 object
는 document
처럼 ID
가 있어야 하기 때문이다.
고유식별번호가 꼭 필요한데 그걸 다 일일이 다 지정해 줘야 할 필요가 없다.
시스템이 알아서 랜덤한 id
를 부여한다.
잠시 mongo console
로 돌아가서 (터미널에서 mongo
를 친다음 show dbs
를 쳐준다.)
(wetube database
폴더가 존재하고 있는데 왜 존재하는지는 모르겠다.
강의에서는 아직 존재 하지 않는 걸로 나오고 있는데 일단 넘어가도록 한다.)
home
에서 새로고침을 하면 아직 아무 영상도 없다.
video
에 대한 정보가 database
에 존재하지 않는다. 이게 무슨 일이냐면
첫 video
를 만든 것은 맞다. 그리고 object
는 javascript
세계에서는 존재한다.
하지만 아직 저장이 안 된 상태 이다.