coding/Node.js

Sequelize Op like - 검색 기능

JIN_Coder 2022. 8. 23. 19:33

프로젝트를 하면서 검색 기능을 만들 기회가 생겼다.

전에 특정한 카테고리를 중심으로 필터 기능을 만들었는데 그때는 findAll을 통해서 where(조건)에 해당 카테고리를 넣어 찾아주면서 필터 기능을 사용하였다.

 

카테고리별 조건에 맞는 데이터 찾기

router.get("/category/:category", async (req, res) => {
  try {
    const { category } = req.params;
    const datas = await Posts.findAll({
      where: { category },
      include: {
        model: Users,
        attributes: ["loginId"],
      },
    });

    res.status(200).json({
      ok: true,
      result: datas.map((e) => {
        return {
          postId: e.postId,
          title: e.title,
          images: e.images,
          category: e.category,
          loginId: e.User.loginId,
        };
      }),
    });
    return;
  } catch (err) {
    res.status(400).json({
      ok: false,
      errorMessage: "카테고리별 게시물 조회를 실패했습니다.",
    });
    return;
  }
});

하지만 매니저님들의 조언으로는 필터 기능을 불러올 때 전에 모든 데이터를 다 내려주었다면, 다시 한번 디비에 접근해서 데이터를 받아오는 게 아니라 프론트에서 반복문을 통해 카테고리별 필터를 접근하는 편이 디비에 부하가 걸리지 않는 방법이라고 말씀해주셔서 이 부분은 상황에 맞게 사용하면 될 것 같다.

 

만약 모든 데이터를 주지 않는 무한 스크롤 같은 기능을 구현했다면 모든 데이터를 주는 게 아니기 때문에 디비에 접근해서 해당 카테고리에 맞는 데이터들을 찾아 보내주어야 하지만, 모든 데이터를 응답으로 주었다면 프론트는 해당 데이터들을 저장하여 사용하기 때문에 뷰에 보여줄 때 반복문을 통해 필터 기능을 만들 수도 있기 때문에 상황에 맞게 사용하면 좋을 것 같다.

 

 

이번에는 검색 기능을 만들어 보았는데 예를 들어 제목이나 내용에서 검색한 키워드가 들어가 있는 데이터 모두를 검색해서 보여주는 기능이다.

'오션뷰'라고 검색을 하였을 때, 제목에 '오션뷰'가 포함되어있거나, 내용에 '오션뷰'가 포함되어있는 데이터를 찾아서 응답 값으로 보내주는 것이다.

이때는 조건만 사용한다면 정말 '오션뷰'라는 키워드 혼자 있어야 해당 조건에 부합하여 찾을 수 있지만,

만약 '오션뷰맛집'처럼 띄어쓰기가 되어있지 않으면 조건에 부합하지 않는 데이터가 된다.

 

때문에 Op.like를 사용하면 '오션뷰'라는 키워드가 들어가 있는지를 확인해서 가져온다.

 

router.get("/search/:searchWord", VerifyMiddleware, async (req, res) => {
  try {
    const { searchWord } = req.params;

    const datas = await Item.findAll({
      include: [
        {
          model: User,
          attributes: ["nickname"],
        },
        {
          model: Comment,
          attributes: ["star"],
        },
        {
          model: Like,
          attributes: ["userkey"],
        },
      ],
      order: [["itemkey", "DESC"]],
      where: {
        [Op.or]: [
          { title: { [Op.like]: `%${searchWord}%` } },
          { location: { [Op.like]: `%${searchWord}%` } },
        ],
      },
    });
    // console.log(datas.length);

    const arr = datas.map((e) => {
      return {
        itemkey: e.itemkey,
        title: e.title,
        img: e.img,
        category: e.category,
        price: e.price,
        location: e.location,
        star: e.Comments,
        like: e.Likes,
        auth: e.User.nickname,
      };
    });

    const user = res.locals.user;
    res.status(200).json({
        likes: [],
        data: arr,
      });
      return;
  } catch (err) {
    console.log(err);
    res.status(400).json({
      result: false,
      errormessage: "검색에 실패했습니다.",
    });
    return;
  }
});

{ title: { [Op.like]: `%${searchWord}%` } }을 통해 제목에서 검색할 키워드를 포함하는 기능을 갖게 한다.

키워드 앞 %가 있다면 '멋진오션뷰'에서 '오션뷰'앞에 어떤 글자가 있더라도 검색할 수 있게 하지만, '오션뷰맛집'은 검색 조건에 충족하지 않는다.

반대로 키워드 뒤에 %가 있다면 '오션뷰맛집'에서는 조건을 충족하지만, '멋진오션뷰' 에서는 충족하지 않기 때문에

키워드 앞뒤로 % 을 넣어 키워드 단독으로 사용하지 않아도 검색이 가능하게 해 준다.

 

현재 제목과, 위치에서 키워드를 검색하고 있으므로

[Op.or]: [
          { title: { [Op.like]: `%${searchWord}%` } },
          { location: { [Op.like]: `%${searchWord}%` } },
        ],

Op.or을 통해 둘 중 하나라도 키워드가 들어가면 검색이 되도록 만들어 주었다.

'coding > Node.js' 카테고리의 다른 글

소켓 / 웹소켓  (0) 2022.09.05
에러 핸들러  (0) 2022.09.03
페이지네이션  (0) 2022.08.23
express HTTPS 설정  (0) 2022.08.20
비밀번호 암호화 - bcrypt  (0) 2022.08.17