More Schema

0_CyberLover_0·2022년 4월 12일
0

Node.JS # 03

목록 보기
12/19

schema가 가질수 있는 옵션을 살펴 보도록 한다.

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

사이트를 살펴 보면 다양한 옵션을 적용 할수 있는데 나중에 한번씩 다뤄 보도록 한다.

한가지 살펴 볼게 있는데

lowercase: boolean, whether to always call .toLowerCase() on the value
uppercase: boolean, whether to always call .toUpperCase() on the value

string을 작성하거나 schemastring이 있으면

lowercase또는 uppercaseboolean(true or false)을 적용 할수 있다.

Mongoose가 값에 대해 toLowercase또는 toUppercase 호출 하도록 하는 거다.

예시를 한번 적요해 보도록 한다.

titleuppercase를 적용 해본다.

video.js에서

  title: { type: String, required: true, uppercase: true },

video를 생성하기 전까지 바뀐 점은 없어 보일테니 새 video를 생성 해본다.

확인해 보면 title을 대문자로 적지 않았는데도 적용이 되어 있는 걸 확인 할수 있다.

mongoose가 알아서 처리 해줬다. uppercasetrue라서 그렇다.

코드를 다시 원상 복귀 해주고 또 뭐가 있는지 살펴 본다.

trim이 있다. trim이 무엇을 하는지 확인해 본다.

trim: boolean, whether to always call .trim() on the value

이 코드는 string 양쪽의 빈 공간들을 없애 준다.

예를 들어 어떤 유저가 이렇게 "hello"적고 거기에 trim을 추가해주면

"hello".trim() "hellow"라고 return 된다.

하지만 누군가 이렇게 " h . " 적은 것에 trim을 추가 해주면

" h . ".trim() "h ."이렇게 결과가 나온다.

"hello".trim()
'hello'
"            h    .".trim()
'h    .'

이렇게 말이다.

양쪽에 있던 스페이스가 사라졌다. 이 기능은 굉장히 유용하다.

그래서 모든 stringtrim을 적어 준다.

지금 현재 경우엔 title이랑 descriptiontrim이 될거다.

hashtagsstring이니 적용해 준다.

Video.js에서

const videoSchema = new mongoose.Schema({
  title: { type: String, required: true, trim: true },
  description: { type: String, required: true, trim: true },
  createdAt: { type: Date, required: true, default: Date.now },
  hashtags: [{ type: String, trim: true }],

이런 operation들은 보통 수동적으로 해야하는데 mongoose덕에 자동으로 할수 있게 되었다.

계속 강조하지만 데이터에 대한 구체적인 설정은 정말 중요하다.

왜냐하면 데이터 타입을 더 구체화 할 수록 trim 같은 것들을 활용 할수 있게 된다.

Mongoose가 언제든 도와 줄수 있게 된다.

match: RegExp, creates a validator that checks if the value matches the given regular expression

match는 정규표현식(regular expression)을 추가하는걸 도와주고

enum: Array, creates a validator that checks if the value is in the given array.

enum도 있고

minLength: Number, creates a validator that checks if the value length is not less than the given number

minLength도 있고

maxLength: Number, creates a validator that checks if the value length is not greater than the given number

maxLength도 활욜 할수 있게 된다.

예시로 한번 적용 해 보도록 한다.

descriptionminLength를 20자로 설정해 본다.

title에는 maxLength를 80으로 설정한다.

Video.js에서

title: { type: String, required: true, trim: true, maxLength: 80 },
  description: { type: String, required: true, trim: true, maxLength: 20 },

이렇게 해주면 title은 최대 80자, description은 최소 20자로 작성 하도록 설정 되었다.

이제 두 가지 선택지가 있는데 하나는 여기까지만 설정하는 거다.

그렇게 하면 에러가 조금 생길거다. 사용자와 해당 코드가 제대로 연결되지 않으면 말이다.

그래서 이 경우엔 upload.pug에 직접 들어가서 minmax를 설정해 준다.

HTML input reference안에 minmax가 존재한다.

https://developer.mozilla.org/ko/docs/Web/HTML/Element/Input

사이트에서 확인해 보면 text에 최소값을 부여하는 minlength

upload.pug에서

block content 
    if errorMessage 
        span=errorMessage
    form(method="POST")
        input(placeholder="Title", requried, type="text", name="title", maxlength=80)
        input(placeholder="Description", requried, type="text", name="description", minlength=20)

이렇게 설정해주면 browser가 도와준다.

새로고침해서 title칸에서 글자를 입력하는데

비디오를 생성할 때 이렇게 최대 글자수를 넘어가는 걸 제한 하고 있다.

이렇게 되면 생각 할수 있는게 이걸 form에서도 할수 도 있겠다.

그런데 굳이 database에 알려줘야 하나?? 둘 다 해줘야 한다.

하나는 사용자를 위한 것인데 만약 누군가가 홈페이지를 해킹을 하면

HTML에 들어가서 이코드를

maxlength=80

삭제 할수 있다. 그렇게 되면 글자 수 제한이 풀리고 해당 기능에 대한 시스템적 보호가 사라진다.

물론 소수의 사용자들만 홈페이지를 검사하고 코드를 변경 할것이다.

하지만 어쨋든 그들로 부터 홈페이지를 보호해야 하니 database에도 해줘야 한다.

그런걸 보호 해주려면 HTML에서 maxLengthminLength를 사용해야 하고

database쪽에서도 이러한 설정을 해줘야 한다.

이렇게 하면 최대, 최소 글자 수를 변형을 이용한 비정상적인 업로드는 할 수가 없게 되는 거다.

이걸로 어느 정도의 보안이 구축 된거다.

default에 대해서도 배웠는데 그로 인해 video를 만들때 meta에 대해 신경 쓸 필요가 없어 졌다.

이제 hashtags에 대해 다뤄 보도록 한다.

사실 지금 상황에서는 완벽한(?) 코드이다. 나중에 video를 수정 할때 문제가 생길 거다.

수정 할때의 form은 업로드 form과 생긴건 똑같지만 다르다.

그럼 이때 새로운 hashtagsstring데이터를 받게 될텐데

그 때 이 코드를 한 번 더 실행 해 줘야 한다.

hashtags: hashtags.split(",").map((word) => `#${word}`),

문제가 발생 하는걸 보고 고쳐야 이해가 더 잘 될수 있다고 생각하기 때문에

이 코드는 나중을 위해 남겨 두기로 한다.

video 수정을 다룰 때 쯤이면 코드를 복붙하는게 좋은 방법은 아니라는 걸 깨달을 수 있을 거다.

이에 대한 방법은 그 때 가서 알아 보도록 한다. 지금은 현재 코드 만으로도 만족 하면 좋을것 같다.

처음 시작 했을 때의 코드를 생각해 보면 코드가 엄청 길었는데 현재는 어느 정도 줄었다.

나중엔 hashtags조차 지저분하게 존재하지 않을 거다.

지금 당장은 아니고 나중에 다뤄 보도록 한다.

이번 파트에 어떤걸 하였는지 다시 한번 복습해 보도록 한다.

schema의 힘은 대단하다. 지금 schema는 데이터의 종류와 필수 여부를 구분할 줄 알고

string의 길이도 검사 할수 있고 trim도 자동으로 실행되고 있다.

여기에 더해 default값들도 설정 되어 있다. 이것이 바로 구체적인 schema의 힘이다.

이제 video를 생성하는 건 다 했다. 이제 해야 할건 홈페이지를 조금 바꾸는 거다.

보다시피 지금 홈페이지는 솔직히 못 생겼다. mixin에서 불려진 이상한 코드들도 있어서

지금 바로 수정해 보도록 한다.

왜냐하면 이제 가짜 database가 없기 때문이다. 바로 video mixin을 바꿔준다.

videotitle을 가지고 있으니깐 두고

video.pug에서

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title

나머지

ul 
            li #{video.rating}/5.
            li #{video.comments} comments.
            li Posted #{video.createdAt}.
            li #{video.views} views.

이 부분은 필요 없으니 삭제해 준다.

descriptionp가 된다. 기억하자. videodescription을 갖고 있다.

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title
        p=video.description

이렇게 수정 해준 다음 새로고침을 해주면 titledescription만 뜨게 된다.

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title
        p=video.description
		small=video.createdAt
        hr

hr을 넣어주면 목록별로 구분선이 생긴게 보인다. 훨씬 보기 좋아 졌다.

small=video.createdAt을 넣어주면 만든 시간이 나와서 좀 더 보기 좋다.

다른건 굳이 보여줄 필요 없이 이정도면 괜찮은 video 리스트 인것 같다.

전체적인 디자인은 나쁘지 않은데 그렇다고 엄청 대단하고 그런것 아니다.

하지만 데이터는 진짜이다. 서버 재시작 기능도 있고 video들은 저장되서 어디 안 도망간다.

database에 저장된 것들이 보여진다.

여기서 꼭 기억해야 하는건 mixin만 바꾸고 있다. mixin이 뭘 하는지 대해서 따로 복습을 해보자.

video.pughome.pug에서 사용되고 있다는 걸 알고 있다.

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title
        p=video.description
        small=video.createdAt
        hr
extends base
include mixins/video

block content 
    each view in videos 
        +video(view)
    else    
        div Sorry nothing found.

그리고 videoControllerhome이란 controller function을 갖고 있는것도 안다.

export const home = async (req, res) => {
  const videos = await Video.find({});
  return res.render("home", { pageTitle: "Home", videos });
};
extends base
include mixins/video

block content 
    each view in videos 
        +video(view)
    else    
        div Sorry nothing found.

home은 모든 video를 찾아내고 videosvideo들로 구성된 array이다.

videoshome template으로 전송 하고 있다.

export const home = async (req, res) => {
  const videos = await Video.find({});
  return res.render("home", { pageTitle: "Home", videos });
};

home templatevideos에 있는 각각의 videovideo mixin을 사용하고 있다.

extends base
include mixins/video

block content 
    each view in videos 
        +video(view)
    else    
        div Sorry nothing found.

video object전체를 mixin으로 보내고 있는 거다.

mixin video(video)
    div
        h4
            a(href=`/videos/${video.id}`)=video.title
        p=video.description
        small=video.createdAt
        hr

video object는 참고로 이거를 가르킨다.

{ "_id" : ObjectId("6254cdf75499452878f5f059"), "title" : "Something with HTML", "description" : "Delicious", "hashtags" : [ "#adfadsfasfa", "#asdfasfdaf" ], "meta" : { "views" : 0, "rating" : 0 }, "__v" : 0 }

mixin이 이 video object들을 얻는 거다. 그리고 video.id링크로 render하고 있다.

그래서 video링크를 하나 클릭하면 url이 해당 영상의 id임을 확인 할수 있다.

http://localhost:4000/videos/6252a57c867de2bae69b9f31

그리고 보다시피 mongoDB가 부여한 id가 좀 이상한 형태인 것도 알수 있다.

흔히 알고 있는 짧은 숫자가 아니라 완전히 랜덤으로 설정된 거다.

아무것도 하지 않아도 이렇게 알아서 만들어 준다. 하지만 문제가 있는데 바로 이런 메세지가 뜬다는 거다.

Cannot GET /videos/6252a57c867de2bae69b9f31

이건 video router때문인데 기억 하다시피 video router는 숫자만 인식하게 되어있다.

이상한 string이 아니라 이건 다음 파트에서 해보도록 한다.

profile
꿈꾸는 개발자

0개의 댓글