이제는 진짜로 영상을 찾아 볼 차례이다.
그래서 Mongoose
, MongoDB
와 소통하기 위해 사용해야 할건 async
랑 await
이다.
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
가 없으면 videos
는 undefined
가 되고
에러가 발생 할거다.
두가지 옵션이 있다. 하나는 이렇게 하는 것이지만 당연히 올바르게 작동 안 할거다.
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 });
};
여기에 videos
를 empty array
로 정의 할수 있는데 여기 안에 videos
를
새로 정의 하는것 대신에 바깥에서 정의된 videos
를 단순히 업데이트만 하는 거다.
이것 또한 한가지 옵션이 될수 있다. 둘중 아무거나 마음에 드는 대로 하면 된다.
그리고 search
화면에 있으면 template
에서는 이미 videos
가 empty array
인 거다.
왜냐하면 keyword
가 있던 없던 videos
는 empty 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 mixin
을 import
해야한다.
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
로 끝나는 제목의 영상을 검색하고 싶다면 그게 가능 하다는 거다.
regular expression
에 대해 한번 알아 본다.
welcome how are you
hello and welcome
이렇게 두 가지 제목이 있다고 가정한다. welcome
을 포함한 제목들을 검색하고 싶다고 한다면
regular expression
칸에 welcome
을 입력 한다.
그러면 둘다 welcome
을 포함하고 있기에 선택 된다.
두가지 옵션이 있다. i
와g
가 있다. g
는 global
을 뜻하고 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
라고 입련한다.
그리고 만약 keyword
만 i
와 RegExp
에 넣으면 이렇게 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
도 생성했다.
search
는 controller
가 필요하다.
이제 req.query
가 URL
에 있는 query
값을 준다는 것도 알았다.
그리고 만약 keyword
가 있으면 그 keyword
로 영상을 검색하는 부분이다.
그 다음 영상을 rendering
하는 거다. 익숙하지 않은 부분이 아마
return res.render("search", { pageTitle: "Search", videos });
이 부분 일 거다.
if (keyword) {
const videos = await Video.find({
title: {
여기에서 const videos
이렇게 하면 안된다. 만약에 하게 된다면 if
문 바깥에 있는
videos
는 undefined
가 될거다.
또한 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
에서 나오는 거다.
Mongoose
는 mongoDB
와 연결해주는 다리 역할이다.