검색 기능 + 가격 및 편의성 추가 + 모델 수정
오늘은 드디어 search 기능을 구현했다. 원래는 몽고DB의 Searh쿼리를 이용하여 구현하였는데, 한글은 제대로 검색이 안 되는 이슈가 존재하였다. (어쩌면 내가 해결 못하는 것일지도.) 그래서 검색 문자를 포함하는 경우 검색 되도록 쿼리를 수정하였다.
오늘의 목표
1. 서치 기능 구현
2. 가격 추가
3. 메뉴 모델 구현
* 혹시나 제가 공부하는 과정을 따라서 실습해 볼 분은 제가 진행한 순서대로 따라오면 될 것 같습니다. 현재까지 아래의 순서를 따릅니다.(깃허브 코드 포함)
몽고DB 검색 구현
app .get ('/searched_cafe', async (req , res )=>{
const searchTerm = req .query .searchingData ;
const results = await Cafe .find ({
$or : [
{ name : { $regex :searchTerm , $options :'i' } },
{ 'menu.name': { $regex :searchTerm , $options :'i' } },
{ repreMenu : { $regex :searchTerm , $options :'i' } }
]
}).sort ({ score : { $meta :'textScore' } })
.select ({ score : { $meta :'textScore' } }); // $meta projection 추가
res .render ('cafe', {cafes :results })
})
위 몽고DB 몽구스 쿼리를 이용하면 유사도가 높은 순으로 결과가 배치된다.
또한 create에서 가격을 추가하였다. 메뉴와 가격을 따로 모델로 만들까 고민하다가 내가 만드는 사이트 규모가 그렇게까지 할 정도로 커지지 않을 것 같아 하지 않았다. 아참 이번에 처음으로 챗GPT를 이용해가며 코딩을 해 봤는데, 챗GPT이거 물건이다. 내가 원하는 것을 완벽히 만들어 주지는 못하지만 오류를 기가막히게 해결해준다. 대안 제시 또한 훌륭하고, 필요하면 레퍼런스 또한 보여준다. 앞으로 안 이용할 이유가 없겠다.
다만 현실 세계의 검색 엔진은 무척 복잡하다. 하지만 내가 만드는 어플리케이션은 이정도면 충분하리라.
html 작업
1. 데이터 받아오기
이번에 막힌 것이 각기 다른 배열로 받은 데이터를 합치는 것이었다. 예를 들어 name에 [1, 2, 3]이 들어오고 price에 [a, b, ,c]가 들어오는 식으로 html을 작성했다.
<h5 >메뉴명 / 가격 </h5 >
<div class ="row">
<input class ='col-8 menuName0'id ="menuName"type ="text"name ="menu[name]"style ="margin-bottom: 3px;"readonly >
<input class ='col-4'id ='price'placeholder = '₩'type ="text"name ="menu[price]"style ="margin-bottom: 3px;">
<input class ='col-8 menuName1'id ="menuName"type ="text"name ="menu[name]"style ="margin-bottom: 3px;"readonly >
<input class ='col-4'id ='price'placeholder = '₩'type ="text"name ="menu[price]"style ="margin-bottom: 3px;">
<input class ='col-8 menuName2'id ="menuName"type ="text"name ="menu[name]"style ="margin-bottom: 3px;"readonly >
<input class ='col-4'id ='price'placeholder = '₩'type ="text"name ="menu[price]"style ="margin-bottom: 3px;">
name속성을 보면 menu라는 오브젝트내에 name들을 넣고 또한 price들을 넣고 있다. 즉,
menu:{
name:[]
price:[]
}같은 형식으로 넘겨버리는 것이다.
여기서 내가 원한 것은
menu:{
name, price
}
menu:{
name, price
} (...)
처럼 여러 개의 메뉴가 개별적으로(병렬적으로?)존재하는 것이었다.
이를 해결하기 위한 방법을 찾아봤지만, 적당한 방법을 찾지 못해 데이터를 받은 쪽에서 배열을 돌며 하나의 오브젝트로 합쳐서 DB에 저장하도록 처리하였다. 아마 조금 더 고급지고 깔끔한 방법이 존재하리라 생각한다.
이 과정에서 js의 오브젝트는 마치 C의 포인터처럼 직접 대입한 후 대입 받은 곳의 값을 바꾸면 본래 변수의 값도 바뀜을 확인하였다.(아마 주소를 가지고 가는 듯 하다)
그래서 얕은 복사라는 방식을 사용하였다.
app .post ('/cafe', async (req , res )=>{//create cafe
console .log (req .body )
const cafeElement = req .body .cafe
let menu = {}
const menuName = req .body .menu .name
const menuPrice = req .body .menu .price
const menuArr =[]
let cnt = 0
for (let n of menuName ){
menu .name = n
console .log ('n', n )
menu .price = menuPrice [cnt ]
let temp = Object .assign ({}, menu )//얕은 복사, =로 할당시 주소를 그대로 가짐(c의 포인터와 유사)
cnt ++
menuArr .push (temp )
}
const cafe = new Cafe (cafeElement );
cafe .menu = menuArr
await cafe .save ();
res .redirect ('/cafe');
})
2. 편의성 추가
이외에 대표메뉴에 세 가지 메뉴를 추가하고 확인을 누르면 그대로 아래 메뉴 인풋에도 그 값이 들어오도록 편의성을 올렸다. 이 과정에서 바닐라JS를 사용하였다.
repMenuBtn .addEventListener ('click', e =>{
e .preventDefault ();
menuName0 .value = repre0 .value ;
menuName1 .value = repre1 .value ;
menuName2 .value = repre2 .value ;
})
리액트를 조금 배운 적이 있지만, 아직 프로젝트에 사용하기 버거움과 동시에 그정도 규모를 가지지 않을 거라는 생각에 사용하지 않고 있다. 최근 프로젝트 때문에 플러터를 배우고 있는데, 이게 끝나면 React 역시 더욱 전진해봐야겠다.
오늘의 결과
+) 정적 파일을 다루는 법을 잊어 함참 헤맸다.
해결:https://doompa.tistory.com/333
댓글