유튜브 클로닝 #6 CRUD (1) CREATE & READ

7710 단어 CRUDyoutube강의CRUD

🔖 강의 범위: #6.15~19

Preview

지난 시간에 db 를 설치, 연결, 데이터 형식 세팅까지 해주었다. 이제 진짜 db와 소통하는 crud 기능을 설치해줄 차례이다.

비디오를 업로드하는 페이지를 만들면서 어떤식으로 CRUD 를 설정할 수 있는지 알아볼 것이다.
그럼 각 기능을 쪼개서 먼저 C(create) 기능부터 만들어보자.
그리고 이어서 R(read) 기능을 통해 만들어진 데이터가 잘 불러와지는지 확인해볼 것이다.
비디오를 업로드하는 페이지를 만들며 새로운 데이터를 데이터베이스에 만들고 읽어오는 작업을 해보자..

강의 내용

step 0. upload 페이지를 만들어준다.

1) upload template
2) controller 에서 getUpload, postUpload
3) router 에서 videos/upload 라우팅 해주고 get, post 각각 기능 추가해줌

step 1. template 손보기: input name

Video model 에 작성한 형식대로 form 은 데이터가 오기를 기대할 것이다.
upload form 이 있는 upload template 으로 돌아가서 input name 에 데이터 형식에 작성했던 키값들을 적어주자.

step 2. controller 손보기: new Model, Model.create

이제 컨트롤러로 돌아와 클라쪽에서 들어온 정보들을 어떻게 다룰지 보자.

1) new Model : 컨트롤러에 데이터형식에 맞춰 새로운 데이터를 만들어주자.

//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}`);
}
  • 이 과정에서 문자열을 split("spliter"), map() 매서드를 배웠다.
  • 참고로 새로운 데이터가 생성됐을 뿐, 아직 db 에 저장되진 않았다.
  • 콘솔에 찍어보면 추가해주지 않은 id 가 부여된 걸 알 수 있는데 new Model 로 새 데이터 생성시 몽구스가 부여해준다.
  • 혹시 데이터형식 타입에 맞지 않게 입력하더라도 (ex. title:String 인데 title:6 으로 설정) 몽구스가 알아서 타입 변경을 model 에 맞게 해준다.
    • 만약 타입 변경이 불가능한 경우라면 (ex. views: Number 인제 views: "lalala" 로 설정) 그 부분은 삭제하고 데이터를 만든다.
  • 데이터 타입 외에 다른 속성을 넣고 싶다면 이렇게 해주면 된다.
    ex. { type: String, required: true, default: Date.now }
    • default 속성 설정시 이 때 속성에 함수가 있다면 () 는 빼고 해줘야 한다. Date.now() (x) Date.now (o)
    • default 속성 설정시 컨트롤러에 굳이 언급해줄 필요 없다. 알아서 디폴트값으로 생성해주니까.
    • 공식 홈페이지에서 mongoose.Schema 에 적용할 수 있는 다양한 속성들을 안내해준다.

2) .save(): 이제 만들어진 데이터를 데이터베이스에 저장하자

1)

await 생성된데이터변수명.save()

🌟 ! 주의: 잊지말자. 데베 다룰 때는 await 걸어서 기다려줘야 한다.

3) Model.create() : 또 다른 옵션

만들 때 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}`);
}

은 같다.

4) try/catch : error 시 에러메세지 창 만들기

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.

5) Read part

5-1. read Home

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)
  }
}

5-2. read Watch

불러와진 데이터 타이틀을 클릭하면 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 →

이렇게 생성한 데이터를 잘 불러와지는지도 잘 확인할 수 있었다.

6) 존재하지 않는 비디오 요청시 띄울 화면 만들기

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 });
}

추가 공부 ?

req.body:
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 collection -> 내 데이터들 모음집이 나온다.
이름이 Video 가 아니라 videos 로 뜨는 이유는, 몽구스가 알아서 제일 첫번쨰는 소문자로 + 끝에 s 를 붙이기 때문이다.

몽구스 스키마 타입 확인
Mongoose 스키마는 Mongoose 모델을 구성하기 위한 객체로 생각할 수 있습니다.
https://mongoosejs.com/docs/schematypes.html

몽구스 스키마 타입 정의
몽구스의 모든 것은 스키마로 시작합니다. 각 스키마는 MongoDB 컬렉션에 매핑되고 해당 컬렉션 내 문서의 모양을 정의합니다.
https://mongoosejs.com/docs/guide.html

.excu
몽구스 매서드 중 다루지 않은 핵심 내용은 .excu 이다. .excu 는 excute(실행하다) 의 약자로 promise 를 따로 걸지 않아도 해당 매서드를 건 statement 에 await 을 걸어준다. 그런 게 있다, 정도로만 이해하고 넘어가자.

요점

  • 데이터베이스의 데이터를 생성(create) 해보았다: Schema() 설정, Model(), Model.create() 또는 new Model(), callback & promise, try/catch
  • 데이터베이스의 데이터를 찾고 읽는(read) 작업도 해보았다: Model.find(), Model.findById(), 이때 promise 필수

좋은 웹페이지 즐겨찾기