프롤로그
캡스톤 프로젝트에 쓸 검색 기능을 어떻게 구현할까 하다가 MongoDB Atlas에서 제공하는 Search Index를 사용하기로 했다. 완전한 단어 또는 문장을 검색하지 않아도 포함된 글자 만으로 결과가 나오도록 했다.
참고 : https://seoyun-is-connecting-the-dots.tistory.com/311
1. Index 생성하기
우선 MongoDB에서 로그인하여 원하는 프로젝트를 선택하고 All Clusters에 들어간다.

Atlas Search에 들어가면 Search Type이 두 가지가 있다. (무료 버전 클러스터. 유료 버전은 다를지 모르겠음..)
○ Atlas Search와 Vector Search의 차이점?
- Atlas Search
- 텍스트 기반 검색 기능
- 특정 단어가 포함된 문서를 검색
- 정렬, 필터링, 범위 쿼리 등 고급 SQL 지원
- 검색 인덱스 별도 생성
- Vector Search
- 유사도 기반 검색 기능
- 이미지, 문장, 추천 시스템 검색
- 정렬, 필터링 지원에 제한적이며 일부 범위 쿼리 지원
- knnVector 인덱스 필요

Visual Editor와 JSON Editor 중에 선택해준다.
○ Visual Editor 와 JSON Editor 비교
- Visual Editor
- 그래픽 기반으로 필드 추가
- 코드 없이 사용 가능
- 초보자에게 추천
- 에러 발생률 적음
- 복잡한 인덱스에는 한계
- JSON Editor
- JSON 형태의 코드 작성
- 세밀한 조정 가능
- 복붙 또는 git 관리 가능
- Visual Editor 보다 많은 기능 제어 가능

필자는 JSON Editor를 사용하고 아래 코드를 작성했다.
board_index
{
"mappings": {
"dynamic": false,
"fields": {
"author": {
"type": "string"
},
"content": {
"type": "autocomplete"
},
"title": {
"type": "autocomplete"
}
}
}
}
user_index
{
"mappings": {
"dynamic": false,
"fields": {
"username": {
"type": "string"
}
}
}
}
제목, 내용, 저자를 검색할 수 있는 board_index와 사용자 이름을 검색할 수 있는 user_index를 생성했다.
이제 코드에 적용해보자.
2. Search Index 를 Node.js에 적용하기
services/search/index.js
class SearchService {
async getSearchAll(query) {
if (!query) {
throw new Error("검색어가 필요합니다.")
}
const board_idx = "board_index"
const user_idx = "user_index"
const [titleResults, contentResults, authorResults, userResults] =
await Promise.all([
//제목
Board.aggregate([
{
$search: {
index: board_idx,
autocomplete: {
query,
path: "title",
},
},
},
]),
//내용
Board.aggregate([
{
$search: {
index: board_idx,
autocomplete: {
query,
path: "content",
},
},
},
]),
//저자
Board.aggregate([
{
$search: {
index: board_idx,
autocomplete: {
query,
path: "author",
},
},
},
]),
//유저
User.aggregate([
{
$search: {
index: user_idx,
autocomplete: {
query,
path: "username",
},
},
},
]),
])
return {
titles: titleResults,
contents: contentResults,
authors: authorResults,
users: userResults,
}
}
}
export default SearchService
처음에는 boardResults 안에 board_index의 path들을 $search로만 묶어서 나열했지만 에러가 났었다.
찾아보니 path별로 구분해야하기 때문에 boardResult도 3개로 나눠줬다.
controllers/search/index.js
export const search = async (req, res) => {
//get 함수에서 문자열을 기대함
const { query } = req.query
//검색어 입력 확인
if (!query || typeof query !== "string") {
return res.status(400).json({ message: "검색어가 필요합니다." })
}
try {
const results = await SearchService.getSearchAll(query)
res.status(200).json(results)
} catch (err) {
console.log(err)
res.status(500).json({ message: "검색 오류" })
}
}
수정 사항
user_index와 board_index의 author를 String 형태로 검색하기 때문에 정확하지 않으면 검색값이 나오지 않는다.
지금 board_index처럼 autocomplete로 바꾸는게 좋을 것 같다.
Capstone GitHub : https://github.com/Knhye/capstone

감사합니다 (‧‧)nnn
'Development > DB' 카테고리의 다른 글
| [JPA] 카테시안 곱 발견 후 해결 과정 (1) (0) | 2025.10.28 |
|---|---|
| [MongoDB] Mongoose Transaction 사용하기 (0) | 2025.05.16 |