🙋‍♀️ Server

[Server] Node.js + MySQL로 찜 기능 만들기

수댕ʕت̫͡ʔ 2024. 12. 28. 10:57

공동 구매 마켓 프로젝트에서 찜하기 기능을 구현했다. 처음에는 어떻게 설계해야할지 고민이 많았는데 그 내용을 정리해보려고한다.

1. 구현해야할 API

  1.  물품 찜하기
  2.  내가 찜한 물품 조회

2. 테이블 설계

CREATE TABLE Wishlists (
    wishlist_id INT PRIMARY KEY AUTO_INCREMENT,    -- 위시 리스트 ID (Primary Key)
    user_id INT NOT NULL,                          -- 사용자 ID (Foreign Key) 
    product_key INT NOT NULL,                      -- 찜한 상품 ID (Foreign Key)
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,-- 생성일
    FOREIGN KEY (user_id) REFERENCES User(user_id) ON DELETE CASCADE, 
    FOREIGN KEY (product_key) REFERENCES Product(product_key) ON DELETE CASCADE, 
    UNIQUE (user_id, product_key)
);

설계의 주요 포인트

  1. Foreign Key:
    • user_id와 product_key는 각각 User와 Product 테이블과 연결되어 있기 때문에 데이터 무결성을 유지하도록했다.
  2. 중복 방지:
    • user_id와 product_key의 조합을 UNIQUE 제약 조건으로 설정해 동일한 물품이 중복 저장되지 않도록 했다.
  3. 연쇄 삭제:
    • ON DELETE CASCADE로 설정해 사용자가 삭제되거나 물품이 삭제되면 관련된 찜하기 데이터도 자동으로 삭제되도록 구현했다.

3. API 구현

1) 물품 찜하기

찜하기는 product_key와 세션에 담긴 user_id를 통해 구현했다.

먼저 user_id와 product_key를 통해 Wishlists 테이블에서 데이터를 조회했다. 이때 데이터가 존재한다면 그 데이터를 삭제, 존재하지 않는다면 데이터를 삽입하도록 했다. 그래야 데이터의 양이 불필요하게 많아지는 것을 방지할 수 있다고 생각했기 때문이다.

exports.postWishlists = async (req, res) => {
  try {
    const userId = req.session.user.user_pk; // 세션에서 user_id 가져오기
    const productKey = req.params.product_key; // URL에서 product_key 가져오기

    // db에서 상태 확인
    const wishlist = await Wishlists.findOne({
      where: { user_id: userId, product_key: productKey },
    });

    if (wishlist) {
      // 위시 리스트에서 삭제
      await wishlist.destroy();
      return res.status(200).send({
        isSuccess: true,
        message: '위시 리스트에서 삭제되었습니다.',
      });
    } else {
      await Wishlists.create({
        user_id: userId,
        product_key: productKey,
      });
      return res.status(200).send({
        isSuccess: true,
        message: '위시 리스트에 추가되었습니다.',
      });
    }
  } catch (error) {
    console.log('err', error);
    return res
      .status(500)
      .send({ isSuccess: false, message: '서버 오류가 발생했습니다.' });
  }
};

 

2) 내가 찜한 물품 조회

내가 찜한 물품은 user_id를 통해 가져왔다. Wishlists 테이블에서 user_id의 product_key의 정보를 모두 가져오고, 이를 이용해 Product 테이블에서 찜한 물품의 정보들을 가져왔다.

exports.getWishlists = async (req, res) => {
  try {
    // 세션에서 사용자 ID 가져오기
    const userId = req.session.user ? req.session.user.user_pk : null;

    if (!userId) {
      // 로그인하지 않은 경우 로그인 페이지로 리다이렉트
      return res.redirect('/auth/login');
    }

    // 찜한 상품 가져오기
    const wishlists = await Wishlists.findAll({
      where: { user_id: userId },
      attributes: ['product_key'],
    });

    if (wishlists.length === 0) {
      return res.render('wishlist', {
        isSuccess: true,
        message: '찜한 상품이 없습니다.',
        products: [],
      });
    }

    const productKeys = wishlists.map((wishlist) => wishlist.product_key);
    const products = await Product.findAll({
      where: { product_key: productKeys },
    });

    res.render('wishlist', {
      isSuccess: true,
      message: '찜한 상품 목록입니다.',
      products,
    });
  } catch (error) {
    console.error('찜한 상품 렌더링 오류:', error);
    res.status(500).send('서버 오류');
  }
};

 

Wishlists 테이블

 

이렇게 찜하기 관련 API를 구현 완료했다.