Statics

0_CyberLover_0·2022년 4월 14일
0

Node.JS # 03

목록 보기
18/19

일단 모든 영상들을 다시 지워준다.

mongodb shell에서 db.videos.remove({})를 해준다.

그리고 잠깐 복습하자면

videoSchema.pre("save", async function () {
  this.hashtags = this.hashtags[0]
    .split(",")
    .map((word) => (word.startsWith("#") ? word : `#${word}`));
});

지난 파트에서 했던 부분이다. 어떤 이벤트가 발생하기 전에 중간에서 가로채서

문서를 수정 할수 있다는걸 배웠다. 지난 파트에서 이렇게 title을 이런식으로 변경하는 법을 했었다.

this.title = "blablabla"

그리고 만약 이대로 두면 저장하는 모든 영상들의 제목은 모두 이렇게 될거다.

pre("save")도 할수 있고 post("save")도 있고 pre(validate")도 있고

많은 middleware가 있다.

https://mongoosejs.com/docs/middleware.html

이 사이트로 가서 middleware를 살펴보면 validate 기타 등등 그외에도 엄청 많다.

이제 기회가 있다. 어떤 기회이냐면 findByIdAndUpdate를 위한 pre mideelware가 없다.

const video = await Video.exists({ _id: 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}`)),
  });

findByIdAndUpdatefindOneAndUpdate를 호출하는데 findOneAndUpdate를 위한

middleware있다.

다만 문제는 findOneAndUpdatesave hook을 호출하지 않는다. 그게 다른 점이다.

그리고 findOneAndUpdate에서는 업데이트 하려는 문서에 접근을 할수가 없다.

save hook 같은 경우에는 여기 pre("save") middleware를 보면

videoSchema.pre("save", async function () {
  this.hashtags = this.hashtags[0]
    .split(",")
    .map((word) => (word.startsWith("#") ? word : `#${word}`));
});

여기에서는 update하는 문서에 접근이 가능하다.

findBy가 아니라 findOneAndUpdate의 경우에는 접근 할수가 없다.

여기저기 손 볼 곳이 좀 있다. 그리고 모든게 다 save에 있을 때 만큼 좋지도 않을 거다.

pre("save")하는 방법을 배웠다. 좋은 방법이다. 하지만 이번 경우에는 그렇게 도움이 되지는 않는다.

왜냐하면 이 기능이 saveupdate 두 군데에 다 필요 하기 때문이다.

그렇기 때문에 지울거다. 방법이 나빠서가 아니라 더 나은 방법으로 하는게 있기 때문이다.

이제 다시 출발선으로 돌아왔다.

video를 생성 할때 hashtags를 직접 수동으로 처리 해야 했다.

나쁘진 않다. 다만 function을 여기 저기 다 복붙해야 한다는거다.

한가지 옵션이 있는데 그 옵션은 여기에다가 function을 만드는 거다.

video.js에서

import mongoose from "mongoose";

export const formatHashtags = (hashtags) =>
  hashtags.split(",").map((word) => (word.startsWith("#") ? word : `#${word}`));

방금 만든 formatHashtags라는 function을 사용해서 이렇게 해준다.

export const postUpload = async (req, res) => {
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      hashtags: formatHashtags,
    });

그러면 똑같은 결과가 나오게 된다.

(뭐가 문제인지 모르겠지만 formatHashtagsimport되지 않아서 직접 했다.)

그리고 이제 해야 할건

export const postEdit = async (req, res) => {
  const { id } = req.params;
  const { title, description, hashtags } = req.body;
  const video = await Video.exists({ _id: id });
  if (!video) {
    return res.render("404", { pageTitle: "Video not found." });
  }
  await Video.findByIdAndUpdate(id, {
    title,
    description,
    hashtags: formatHashtags(hashtags),
  });

이곳에다가 formatHashtags를 입력하고 hashtags를 필요로 하니까 request.body에서부터 가져온다.

export const postUpload = async (req, res) => {
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      hashtags: formatHashtags(hashtags),

이부분도 똑같이 해주면 된다. 이것도 괜찮다. 나쁘지 않은 방법이다.

지금 function을 하나 가지고 있고 그 functionhashtags를 인수로 받고

function은 해시태그 arrayreturn한다.제대로 작동 하는지 테스트해 본다.

upload video를 선택하고 각 input에다가 정보를 입력하고 실행하면 업로드 성공

해시태그를 확인하러 가서 보면 제대로 작동한다.

하지만 다른 방법도 있다. 그걸 알아 보도록 한다.

그건 바로 static이다. 알다시피 video.findById()를 굉장히 자주 사용 하고 있다.

video.create()도 사용하고 있고 video모델의 function들을 많이 쓰고 있다.

video.exists()도 있다.중요한 건 이런 function들을 만들 수 있고 그걸 어떻게 하는지 보겠다.

https://mongoosejs.com/docs/guide.html

여길 살펴 보면

animalSchema.static('findByBreed', function(breed) { return this.find({ breed }); });

그래서 static을 생성하기 위해서 필요한 것은 schema.static이랑 function

만들고자 하는 static의 이름이다. 그러면 준비는 끝이다.

그러니 여기로 와서 videoSchema.static

video.js에서


videoSchema.static("formatHashtags", function (hashtags) {
  return hashtags
    .split(",")
    .map((word) => (word.startsWith("#") ? word : `#${word}`));
});

const Video = mongoose.model("Video", videoSchema);

export default Video;

static의 이름은 formatHashtag 이렇게 그리고 function을 받는다.

document를 보면 원하는 아무 argument나 다 받는다.

이 경우에는 hashtagsargument로 받고 그리고 나서 hashtags를 이대로 가져와서 return하는 거다.

그리고 전에 썼던 부분은 당연히 필요 없으니 지워 준다. 몇가지 에러가 있다.

존재하지 않는걸 import하려고 하니까 당연한 거다.

export const postEdit = async (req, res) => {
  const { id } = req.params;
  const { title, description, hashtags } = req.body;
  const video = await Video.exists({ _id: id });
  if (!video) {
    return res.render("404", { pageTitle: "Video not found." });
  }
  await Video.findByIdAndUpdate(id, {
    title,
    description,
    hashtags: Video.formatHashtags(hashtags),
  });
  return res.redirect(`/videos/${id}`);
};

export const getUpload = (req, res) => {
  return res.render("upload", { pageTitle: "Upload Video" });
};

export const postUpload = async (req, res) => {
  const { title, description, hashtags } = req.body;
  try {
    await Video.create({
      title,
      description,
      hashtags: Video.formatHashtags(hashtags),
    });

그리고 이제 video.formatHashtags()가 있으니 적용 해준다.

body에서 딴 hashtagsargument로 입력하는 거다.

req.body에서 따온 hashtags이다.

이제 직접 만든 functionformatHashtags를 통해 접근이 가능해 졌다.

당연히 이름은 똑같아야 하지만 그렇게만 해주면 끝이다.

각자의 특별한 static function을 만들수 있다는 건 엄청 대단한 거라고 생각한다.

video.findById,video.exists 등등을 쓸수 있듯이 video.formatHashtags도 쓸수 있는거다.

다른 function을 어디서 import할 필요도 더이상 없다.

Videoimport하면 formatHashtags도 따라 온다.

그럼 다시 한번 잘 작동 하는지 테스트 해보겠다. upload video를 해본다.

그리고 다시 Edit Video도 확인한다. 잘 된다.

function은 이제 video에 포함 되어 있다.

그래서 video.formatHashtags로 사용 할수 있는거다.

직접 video function을 아무거나 만들수 있다는건 정말 대단한거다.

물론 middleware도 훌룡하다. 지난 파트에서 배웠지만 또한 훨씬 유용하다.

예를 들면 만약 유저를 생성해야 한다면 유저를 생성하기 전에 비밀번호를 암호화 해야 던가

하지만 이것도 완전 유용하다. 직접 Video function을 커스터 마이징 해서 만드는거 말이다.

다시 비디오들을 삭제해 보도록 한다.

db.videos.remove({})해주면 home으로 가서 새로고침하면 비디오가 하나도 안 남게 된다.

다시 upload video를 해본다. 그러면 역시나 function이 제대로 작동하고 있다.

지금부터 할거는 mixin을 수정해서 hashtags가 보이도록 한다.

mixin폴더로 가서 video.pug.으로 가면

그전에 기억해야 할것이 video에는 해시태그들이 array형식으로 저장되어 있다.

아마 이런 걸 할수 있다는걸 기억해야 한다.

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title
        p=video.description
        ul
            each  hashtag in video.hashtags
                li=hashtag 
        small=video.createdAt
        hr

이렇게 해주면 이제 video.hashtags 안에 있는 해시태그들이 다 보여지게 된다.

새로고침하면 바로 여러 해시태그들을 보여 주고 있다.

감사하게도(?) 지금 반복되는 코드가 싫어서 지금 현재 필요한 static function을 만드는 법을 알았다.

이제 Video.formatHashtags() function이 있다.

그리고 지난 파트에서는 pre("save") middleware를 사용하는 법도 알았다.

profile
꿈꾸는 개발자

0개의 댓글