s e o p p o r t . l o g

Today I Learned

[클룸] DB의 View 사용하기

Seo Ji Won 2024. 4. 23. 16:28

문제 상황

개발 과정에서 특정 클래스 정보와 관련된 다양한 필터링을 중첩해서 사용자가 원하는 클래스를 찾을 수 있도록 해야했다.

다른 필터링 조건은 class 테이블에서 바로 걸러서 가져올 수 있었다. 그래서 query문에 메서드를 추가하는 식으로 중첩 필터링을 할 수 있었다.

하지만 이번에 구현하려하는 평일 / 주말 필터링은 date 테이블과 조인을 해야하고, date 테이블에는 요일 정보가 있는 것이 아니라 2024-03-27 이런식으로 날짜 정보만 있었기 때문에 sql 문으로 따로 요일 정보를 추출해서 비교해야했다.

이것을 rpc로 처리하자니 아예 필터링 로직 자체를 sql에서 하도록 갈아 엎어야 했는데 시간이 촉박한지라 그렇게는 안될 거같았다

그래서 방법을 찾아보았는데 DB의 View기능을 사용하기로 했다.

View를 이용해서 class 테이블과 date 테이블을 조합하고, 각 클래스의 날짜 정보를 가져와서  EXTRACT(DOW) 라는 PostgreSQL 메서드를 이용해서  요일 정보를 추출한 days_of_week을 배열로 나타내도록 해서 뷰를 생성했다.

내가 원하는 방식으로 조합한 데이터로 미리 테이블을 만들어두는 느낌이라고 생각하면 될 것 같다

그런다음 클라이언트에서는 테이블을 직접 참조하는 것이 아니라 뷰를 참조하도록 해서 내가 원하는 정보를 담고 있는 뷰에서 정보를 가져오도록 했다.

따라서 정보는 다음과 같이 나오게된다. (6, 0 = 주말(토,일) 1,2,3,4,5 = 평일(월,화,수,목,금))

{
        "user_id": "21ac1fb5-7898-4e1a-94ec-e64770ae9407",
        "class_id": "6a18f043-7514-4c29-8817-660e0646d2cd",
        "category": "공예&공방",
        "title": "나만의 향기를 담은 캔들 만들기 클래스",
        "description": "향기로운 캔들로 당신의 공간을 더욱 특별하게 만들어 보세요. '나만의 향기를 담은 캔들 만들기' 클래스에서는 다양한 향과 색상을 조합하여, 나만의 개성이 담긴 캔들을 직접 제작해 볼 수 있는 기회를 제공합니다. 캔들 만들기의 기초부터 시작하여, 재료 선택, 향 조합, 색상 선택, 그리고 캔들을 완성하는 과정까지 전문가의 지도 하에 체험할 수 있습니다.",
        "min_people": 5,
        "price": 20000,
        "location": "서울 성동구 서울숲길 46 (성수동1가)",
        "quantity": 10,
        "detail_location": "2층 2101호",
        "total_time": 1,
        "image": [
            "https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/classImages/uploads/6a18f043-7514-4c29-8817-660e0646d2cd_jullliia_Y98LjDhW9S4_unsplash.jpg",
            "https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/classImages/uploads/6a18f043-7514-4c29-8817-660e0646d2cd_jon_tyson_KURRbHLdHkQ_unsplash.jpg",
            "https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/classImages/uploads/6a18f043-7514-4c29-8817-660e0646d2cd_martipaan_QagIzHwsy4A_unsplash.jpg",
            "https://hdurwturhsczrdeugmon.supabase.co/storage/v1/object/public/classImages/uploads/6a18f043-7514-4c29-8817-660e0646d2cd_hanna_balan_YasQvzPbGOQ_unsplash.jpg"
        ],
        "class_type": "오프라인 클래스",
        "difficulty": "입문",
        "active": null,
        "hashtag": [
            "캔들"
        ],
        "days_of_week": [
            1,
            3,
            5
        ],
        "wish": [
            {
                "user_id": "ffc64c28-7bd1-4ca0-9f38-ba9475f7298a"
            },
            {
                "user_id": "7d85ab1a-5630-45d3-9135-8f0782c22113"
            }
        ]
    },

 

클라이언트에서 사용자가 평일/주말 선택한 값을 가지고와서 평일이면 1~5 배열, 주말이면 0,6 배열로 생성해서 overlaps라는 supabase 메서드로 불러온 뷰의 days_of_week 배열 값들 중에 dayArray에 하나라도 일치하는 것이 있다면 true를 반환하도록 필터링하였다. 

따라서 평일, 주말 모두 수업이 있는 클래스는 평일/주말 중 하나를 선택했을 때도 나오게 되고,

평일에만, 주말에만 수업이 있는 클래스는 그에 맞춰서 필터링이 된다.

  let query = supabase
    .from('classes_with_days3') //View 참조
    .select(`*, wish(user_id)`, { count: 'exact' })
    .range(PageNumber, PageNumber + limit - 1); // range란? (a,b) a번째부터 b번째까지의 데이터만 가져오는 메서드 ex 1페이지 0~9 2페이지 10~19

  //중략
  
  if (filters.selectedPrice) {
    if (filters.selectedPrice.min !== undefined && filters.selectedPrice.max !== undefined) {
      query = query.gte('price', filters.selectedPrice.min).lte('price', filters.selectedPrice.max);
    }
  }

  if (filters.selectedDayType) {
    const dayArray = filters.selectedDayType === '주말' ? [0, 6] : [1, 2, 3, 4, 5];
    query = query.overlaps('days_of_week', dayArray); // overlaps: 두 배열이 하나 이상의 공통 요소를 가지고 있을 때 true를 반환
  }


  const { data: classInfos, error, count } = await query;
  if (error) {
    console.error('클래스 정보들 불러오기 오류 => ', error);
    throw new Error(error.message);
  }
  const totalCount = count ?? 0;
  const nextPage = PageNumber + limit < totalCount ? page + 1 : undefined;

  return { classInfos, nextPage }; 
};