Search #02

0_CyberLover_0·2022년 4월 14일
0

Node.JS # 04

목록 보기
2/19

이제는 진짜로 영상을 찾아 볼 차례이다.

그래서 Mongoose, MongoDB와 소통하기 위해 사용해야 할건 asyncawait이다.

videoController.js에서

export const search = async (req, res) => {
  const { keyword } = req.query;
  if (keyword) {
    const videos = await Video.find({
      title: keyword,
    });
    return res.render("search", { pageTitle: "Search", videos });
  }
  return res.render("search", { pageTitle: "Search" });
};
    const videos = await Video.find({
      title: keyword,
    });

여기에선 원하는건 뭐든지 검색 할수 있다. 이 경우엔 보다시피 filter expression을 보낼거다.

예를 들자면 제목이 query에서 온 keyword랑 같은 경우를 찾는거다.

그리고 이제 이 영상을 res.render로 보낸건데

  return res.render("search", { pageTitle: "Search" });

이부분을 반복할 건데 괜찮다. 하지만 이번엔 여기에 videos를 추가하는 거다.

이제 search.pug템픔릿이랑 똑같은 검색 페이지를 렌더링 할건데

한가지 차이점은 videos array가 추가 되었다는 거다. 지금은 모르지만 비어 있을수 도 있다.

현재 상태가 별로 좋지 못하다. 하지만 이렇게 해야만 하는 이유는

export const search = async (req, res) => {
  const { keyword } = req.query;
  if (keyword) {
    const videos = await Video.find({
      title: keyword,
    });
  }
  return res.render("search", { pageTitle: "Search", videos });
};

이렇게 여기에 videos를 추가 할수는 없기 때문이다.

왜냐하면

  const { keyword } = req.query;

여기랑

  if (keyword) {
    const videos = await Video.find({
      title: keyword,
    });

여기에는 videos가 존재하지 않기 때문이다.

그러니까 예를 들어 만약에 keyword가 없다면 videos도 존재하지 않는다.

export const search = async (req, res) => {
  const { keyword } = req.query;
  return res.render("search", { pageTitle: "Search" });
};

이런식이라면 말이다.

다시 설명하자면 만약 검색을 시작할때 마다 keyword가 없으면 videosundefined가 되고

에러가 발생 할거다.

두가지 옵션이 있다. 하나는 이렇게 하는 것이지만 당연히 올바르게 작동 안 할거다.

  if (keyword) {
    const videos = await Video.find({
      title: keyword,
    });

왜냐하면 videos는 이 버블 안에 있다. videos는 이 버블 바깥 세상과는 공유 되지 않는다.

videos는 딱 이 버블 안에서 만 정의되어 있다.

또 다른 옵션은

export const search = async (req, res) => {
  const { keyword } = req.query;
  let videos = [];
  if (keyword) {
    videos = await Video.find({
      title: keyword,
    });
  }
  return res.render("search", { pageTitle: "Search", videos });
};

여기에 videosempty array로 정의 할수 있는데 여기 안에 videos

새로 정의 하는것 대신에 바깥에서 정의된 videos를 단순히 업데이트만 하는 거다.

이것 또한 한가지 옵션이 될수 있다. 둘중 아무거나 마음에 드는 대로 하면 된다.

그리고 search화면에 있으면 template에서는 이미 videosempty array인 거다.

왜냐하면 keyword가 있던 없던 videosempty array이기 때문이다.

만약 keyword가 있다면 videos arrar는 업데이트 될거다.

이게 let을 사용하는 이유이다.

이제는 template을 좀더 잘 그려 보도록 한다.

search.pug에서

extends base.pug
include mixins/video

block content 
    form(method="GET")
        input(placeholder="Search by title",name="keyword", type="text")
        input(type="submit", value="Search now")

    each video in videos 
        +video(video)    

간단히 video mixin을 사용 할거다. 이 경우에는 video mixinimport해야한다.

homePage에 어떻게 import를 하냐면 include만 하면 된다.

search가 처음 시작 할때에는 video가 비어 있으니까 지금은 아무런 영상도 보이지 않을거다.

이제 웹사이트를 제대로 만들때 다시 와서 이 search page를 좀더 꾸며 볼거다.

현재 search page에서 존재하고 있는 제목을 검색하면 찾아서 띄워 준다.

export const search = async (req, res) => {
  const { keyword } = req.query;
  let videos = [];
  if (keyword) {
    videos = await Video.find({
      title: keyword,
    });
    console.log(videos);
  }
  return res.render("search", { pageTitle: "Search", videos });
};

이제 console을 추가해서 작동 시켜 본다. 새로고침하고 console로 가보면

해당 비디오의 정보까지 다 띄워 준다.

extends base.pug
include mixins/video

block content 
    form(method="GET")
        input(placeholder="Search by title",name="keyword", type="text")
        input(type="submit", value="Search now")

    div
        each video in videos 
            +video(video)    

이젠 div안에 집어 넣어 준다. 이제는 영상을 검색하면 영상이 제대로 찾아 진다.

검색 방식을 좀더 개선 할 필요가 있다.

왜냐하면 영상을 검색하려고 제목을 토씨 하나 안틀리고 입력하긴 싫다.

제대로 작동을 하긴 하지만 regular expression을 써서 검색 하게 한다.

regular expression은 여러가지를 지정 할수 있게 해준다.

예를 들면 특정 단어로 끝나는 제목을 검색한다던가 특정 단어를 포함한 제목이라던지

특정 단어로 시작하는 제목도 검색 할수 있게 되는 거다.

그러니까 만약 HTML로 끝나는 제목의 영상을 검색하고 싶다면 그게 가능 하다는 거다.

https://www.regexpal.com/

regular expression 에 대해 한번 알아 본다.

welcome how are you
hello and welcome

이렇게 두 가지 제목이 있다고 가정한다. welcome을 포함한 제목들을 검색하고 싶다고 한다면

regular expression 칸에 welcome을 입력 한다.

그러면 둘다 welcome을 포함하고 있기에 선택 된다.

두가지 옵션이 있다. ig 가 있다. gglobal을 뜻하고 i는 대소문자 무시

ignore case를 의미 한다.

그래서 대문자 W나 소문자 w나 아무런 문제 없이 똑같이 작동 한다.

이번엔 welcome이라는 단어로 끝나는 제목만 검색하고 싶다고 한다면 그럴땐 이렇게 검색한다.

welcome$ 이렇게 입력해 준다. 그러면 마지막 단어에 welcome이 포함된 것만 색칠 된다.

이번엔 welcome으로 시작하는 제목만 검색 하고 싶다면 이렇게 검색해준다.

^welcome 이렇게 해주면 된다.

이제 query에 이런 옵션들을 추가 해주면 된다.

keyword와 정확하게 일치하는 제목을 가진 영상만 찾는게 아니라 예를 들면 주어진

keyword로 시작하는 제목을 가진 영상도 검색 할수 도 있다.

혹은 keyword를 포함하고 있거나 keyword로 끝나거나

이제 그걸 하기 위해서는 regex라는 연산자(operator)를 써야한다.

regular expression의 약자이다.

export const search = async (req, res) => {
  const { keyword } = req.query;
  let videos = [];
  if (keyword) {
    videos = await Video.find({
      title: {
        $regex: new RegExp(keyword, "i")
      },
    });
    console.log(videos);
  }
  return res.render("search", { pageTitle: "Search", videos });
};
$regex: new RegExp(keyword, "i")

여기에 보다시피 regular expression을 보낼 수 있다.

(다른 것들도 많은데 만약 숫자로 뭔가를 하고 싶다면 greater than도 쓸수 있다.

$gt: 3 이런식으로 말이다. 예를 들자면 3보다 더 많은 뷰 수를 가진 영상만 보이도록

필터링 할수도 있을거다.)

이 경우에는 regex를 사용 한다. 간단하게 new RegExp라고 입련한다.

그리고 만약 keywordiRegExp에 넣으면 이렇게 regular expression안에

keyword를 집어 넣으면 contain 방식의 regular expression을 생성하게 된다.

그말은 제목에 keyword를 포함하는 영상들을 찾을 거라는 소리이다.

새로고침해준 다음에 search page로 가서 한 단어가 포함된 검색을 하면 검색이 된다.

이게 포함(contains)이다. 아니면 원한다면 제목이 keyword로 시작하는 영상만 찾을수도 있다.

$regex: new RegExp(`^${keyword}`, "i"),

이렇게 해주면 된다. 잘 작동 한다.

아니면 끝나는 단어로 검색하게 할수도 있다.

$regex: new RegExp(`${keyword}$`, "i"),

이렇게 해준다. 마지막으로 끝나는 단어도 잘 작동한다.

이게 가능한건 MongoDB에 아주 훌륭한 필터 엔진 덕분이다.

Mongoose가 아니다. MongoDB가 한거다.

굉장히 많은 operator가 있다. 그리고 이제 훌륭한 search page를 만들었다.

봤다시피 여태 배운걸 응용한 것일 뿐이다. router부터 시작해서 search도 생성했다.

searchcontroller가 필요하다.

이제 req.queryURL에 있는 query값을 준다는 것도 알았다.

그리고 만약 keyword가 있으면 그 keyword로 영상을 검색하는 부분이다.

그 다음 영상을 rendering하는 거다. 익숙하지 않은 부분이 아마

return res.render("search", { pageTitle: "Search", videos });

이 부분 일 거다.

  if (keyword) {
   const videos = await Video.find({
      title: {

여기에서 const videos이렇게 하면 안된다. 만약에 하게 된다면 if문 바깥에 있는

videosundefined가 될거다.

또한 if 바깥의 코드들과 videos를 공유 할수도 없다.

왜냐하면 이 constant는 이 if문 안에서만 존재하기 때문이다.

그래서 포괄적으로 다 포함하는 let videos array가 필요 한거다.

    videos = await Video.find({

그리고 여기서 업데이트가 되는 거다.

{
      title: {
        $regex: new RegExp(`${keyword}$`, "i"),
      },
    });

그리고 이건 아무 상관이 없다. 왜냐하면 if 문 안에 있으면 바깥에 있는 것들에게도 접근이 가능하다.

regular expression에 대해서도 조금 더 배웠다.

왜냐면 router에서도 regular expression을 썼었고

$regex: new RegExp(`${keyword}$`, "i"),

그리고 이제 regex operator도 있다.

만약 mongoDB에서 가능한 여러가지 옵션들을 살펴보면 정말로 여러가지를 할수 있다.

예를 들면 regex로 검색할 수도 있고 exists,and,not,or,nor.등등

이런 것들도 할수 있다. equals,greager than, greater than equals등등

db.inventory.find( { qty: { $gte: 20 } } )

예시를 보면 qty가 20보다 큰 걸 찾는 거다.

정말 많은 옵션들이 있다. 많은 것들이 다 mongoDB에서 나오는 거다.

MongoosemongoDB와 연결해주는 다리 역할이다.

profile
꿈꾸는 개발자

0개의 댓글