Node.js

node>검색기능 만들기 1

연습노트 2024. 9. 19. 09:26

오늘은 게시물의 제목 검색기능 같은걸 만들어봅시다.

실은 알아서 다 할 수 있기 때문에 강의 끄고 알아서 해봅시다.

혼자 코드를 짜고 싶으면 어떻게 하랬습니까

검색기능이 어떻게 동작하는지 한글로 설명부터 하고 그대로 코드로 옮기면 됩니다.

 

1. 검색 UI 하나 만들고 거기에 "안녕" 이라고 검색어를 입력해서 서버로 전송하면

2. 서버는 DB에서 "안녕"이 포함된 제목을 가진 게시물들을 찾아서

3. 그 게시물들을 ejs 파일에 넣어서 유저에게 보내주기

 

근데 안녕이란 단어가 포함된 document들을 찾아오는 법은 아직 안배웠죠? 

안배운건 당연히 따로 검색해보면 됩니다. 힌트는 정규식 쓰면 쉽습니다.

찾아봐도 모르겠으면 일단은 그냥 제목이 ‘안녕’이랑 정확히 일치하는 글만 찾아오셔도 봐드림

 

 

 

 

 

1. 검색 UI 만들기

 

그냥 인풋이랑 버튼 하나 만들면 끝입니다.

 

(list.ejs)

<input class="search">
<button class="search-send">검색</button> 

 

.search {
  margin-left: 20px;
  padding: 5px;
}
.search-send {
  padding: 6px 10px;
  background: lightgray;
  border: none;
  border-radius: 5px;
  vertical-align: middle;
} 

전 이렇게 디자인해봤습니다.

 

그리고 버튼 클릭하면 서버로 검색어가 전송이 되어야 하는데

그런건 폼태그 쓰거나 fetch() 쓰면 됩니다.

하지만 귀찮은 경우 더 쉽게 GET요청할 수도 있습니다.

 

 

(list.ejs 하단)

<script>
  document.querySelector('.search-send').addEventListener('click', function(){
    let 입력한거 = document.querySelector('.search').value
    location.href = '/search?val=' + 입력한거
  })
</script>

하단에 script 태그 열어서 

1. 검색버튼 클릭하면

2. /search로 GET요청해달라고 했습니다.

실은 location.href는 페이지 바꾸라는 뜻인데 그게 GET요청 아니겠습니까.

3. 그리고 <input>에 입력한 값을 가져와서 query string 으로 집어넣어서 GET요청했습니다.

 

 

 

 

 

2. 서버는 DB에서 검색어가 포함된 게시물을 찾아옴

 

서버는 누가 /search로 GET요청이 들어오면

검색어가 글제목에 들어있는 모든 document를 찾아오면 된다고 적은 것 같군요.

구현해봅시다.

 

app.get('/search', async (요청, 응답) => {
  let result = await db.collection('post').find( {title : 요청.query.val} ).toArray()
}) 

.find(조건).toArray() 쓰면 조건에 맞는 모든 document를 찾아옵니다.

남의 말 믿지 말고 진짜인지 출력해봅시다.

 

 

 

 

 

3. ejs에 넣어서 유저에게 보내줌

 

app.get('/search', async (요청, 응답) => {
  let result = await db.collection('post').find( {title : 요청.query.val} ).toArray()
  응답.render('search.ejs', { 글목록 : result })
}) 

그래서 그 결과를 ejs 페이지로 보내면 될 것 같아서 search.ejs 페이지도 하나 만들어봤습니다.

search.ejs 내용은 그냥 list.ejs 그대로 복붙했습니다.

그럼 진짜 잘 되는지 검색기능을 테스트해보도록 합시다. 

 

 

 

 

Q. 근데 제목이 정확히 일치하는 것만 가져오는데요?

왜 그렇겠습니까  

여러분들 뭔가 안되거나 그러면 그건 컴퓨터탓이아니라 여러분들이 코드를 그렇게 짜서 그럴 뿐입니다. 

 

.find( { title : '바보' } ).toArray()

이렇게 find() 안에 조건을 주면 이게 무슨 뜻이게요?

title이 '바보'와 정확히 일치하는걸 가져오라는 뜻입니다.

그래서 그렇게 코드짜놨을 뿐이라 정확히 제목이 '바보'인 게시물만 가져올 뿐입니다.

 

이게 싫고 "이 단어를 포함하는걸 전부 가져오라고" 필터링 하고 싶으면

검색해보면 아마 여러가지 방법이 나올텐데 

가장 쉽고 간단한건 정규식이 있습니다.

 

 

 

 

 

 

정규식으로 특정문자가 포함된 모든 document 찾아오기

 

app.get('/search', async (요청, 응답)=>{
  let result = await db.collection('post').find({title : {$regex : 요청.query.val} }).toArray()
  응답.render('search.ejs', {글목록 : result})
}) 

$regex라는 연산자를 쓰면 "특정 문자와 일치하는"게 아니라

"특정 문자를 포함하는" 모든 결과를 찾아올 수 있습니다.

관계형 DB였으면 LIKE 연산자 썼을 텐데 MongoDB는 정규식 씁니다.

 

정규식 문법 전부 쓸 수 있으니까 정규식 잘 알고 있으면 유용할텐데

실은 간단한거 말고는 정규식은 많이 쓰진 않습니다.

느려터져서 그렇습니다.

 

 

 

Q. 왜 느려터짐?

왜 느리냐면 컬렉션의 document를 하나하나 전부 까봐야하기 때문에 그렇습니다.

예를 들어 document가 1억개 있는데 그 중에서 '안녕' 이라는 단어가 들어있는 것만 가져오라고 하면 

컴퓨터는 1억개의 document를 전부 다 까서 확인해봅니다.

그래서 document가 많을 수록 시간이 오래걸리는데

속도 문제를 해결하고 싶으면 데이터베이스에 index라는걸 만들어두면 됩니다.

궁금하면 다음 시간에 index가 뭔지 알아보도록 합시다.