221023_광고 관리 플랫폼 대행사 센터 제작 37_광고 관리 페이지 (소재 리스트) 수정 및 통계 기능 구현

창고·2022년 10월 24일
0

해당 게시글은 개인 프로젝트인 "광고 관리 플랫폼 대행사 센터 제작"
#108 "광고 관리 페이지 (소재 리스트) 수정 및 통계 기능 구현" 이슈를 다루고 있습니다.

1. 진행 사항

(1) 요약

  • 통계 쿼리 작성 및 테스트 -> QueryDSL로 변환
  • Mock Data 수정
  • 일일 통계 기능 구현
  • 최근 1주일 간의 통계 보기 기능 구현
  • 최근 30일 간의 통계 보기 기능 구현
  • 페이지 수정
  • 소재 실적 통계 기능 수정

(2) 세부 내용

  • QueryDsl을 통해 통계 기능 구현
    • 미리 작성한 SQL을 QueryDsl로 변환하였음
    • 통계 데이터를 처리할 PerformanceStatisticDto / Response를 사용, Projections.fields를 통해 필드에 직접 값을 주입하는 방식 선택
    • CTR, CVR, CPA, ROAS 와 실적 데이터 문자열 변환 등은 Dto 내부 메소드를 통해 세팅
  • 캠페인 별 소재 실적 통계
SELECT
	c.id AS creative_id,
	c.name AS creative_keyword,
	c.budget AS creative_bidingPrice,
	c.deleted AS creative_deleted,
	c.activated AS creative_activated,
	sum(p.view),
	sum(p.click),
	sum(p.conversion),
	sum(p.spend),
	sum(p.purchase)
FROM performance as p
LEFT JOIN creative AS c ON c.id = p.creative_id
LEFT JOIN campaign AS ca ON ca.id = c.campaign_id
WHERE p.created_at BETWEEN '2022-10-15' AND '2022-10-19' AND ca.id = 1 AND c.deleted = false
GROUP BY c.id
    public List<PerformanceStatisticsDto> findByCampaign_IdAndStatisticsDefault(@Param("id") Long campaignId,
                                                                                @Param("startDate") LocalDate startDate,
                                                                                @Param("lastDate") LocalDate lastDate
    ) {
        List<PerformanceStatisticsDto> results = jpaQueryFactory
                .select(Projections.fields(PerformanceStatisticsDto.class,
                        performance.creative.id.as("creativeId"),
                        performance.creative.keyword.as("keyword"),
                        performance.creative.bidingPrice.as("bidingPrice"),
                        performance.creative.deleted.as("deleted"),
                        performance.creative.activated.as("activated"),
                        performance.view.sum().as("view"),
                        performance.click.sum().as("click"),
                        performance.conversion.sum().as("conversion"),
                        performance.purchase.sum().as("purchase"),
                        performance.spend.sum().as("spend")
                ))
                .from(performance)
                .leftJoin(performance.creative, creative)
                .leftJoin(creative.campaign, campaign)
                .where(
                        performance.createdAt.between(startDate, lastDate),
                        campaign.id.eq(campaignId),
                        performance.creative.deleted.eq(false)
                )
                .groupBy(performance.creative.id)
                .fetch();

        for (PerformanceStatisticsDto result : results) {
            Long spend = result.getSpend();
            Long view = result.getView();
            Long click = result.getClick();
            Long conversion = result.getConversion();
            Long purchase = result.getPurchase();

            result.setCreativeIndicator(spend, view, click, conversion, purchase);
        }

        return results;
    }
  • 특정 캠페인의 전체 소재 실적 통계
SELECT
	sum(p.view),
	sum(p.click),
	sum(p.conversion),
	sum(p.spend),
	sum(p.purchase)
FROM performance as p
LEFT JOIN creative AS c ON c.id = p.creative_id
LEFT JOIN campaign AS ca ON ca.id = c.campaign_id
WHERE p.created_at BETWEEN '2022-10-15' AND '2022-10-19' AND ca.id = 1 AND c.deleted = false
GROUP BY c.id
    public List<PerformanceStatisticsDto> findByCampaign_IdAndTotalStatisticsDefault(@Param("id") Long campaignId,
                                                                                @Param("startDate") LocalDate startDate,
                                                                                @Param("lastDate") LocalDate lastDate
    ) {
        List<PerformanceStatisticsDto> results = jpaQueryFactory
                .select(Projections.fields(PerformanceStatisticsDto.class,
                        performance.view.sum().as("view"),
                        performance.click.sum().as("click"),
                        performance.conversion.sum().as("conversion"),
                        performance.purchase.sum().as("purchase"),
                        performance.spend.sum().as("spend")
                ))
                .from(performance)
                .leftJoin(performance.creative, creative)
                .leftJoin(creative.campaign, campaign)
                .where(
                        performance.createdAt.between(startDate, lastDate),
                        campaign.id.eq(campaignId),
                        performance.creative.deleted.eq(false)
                )
                .groupBy(performance.creative.campaign.id)
                .fetch();

        for (PerformanceStatisticsDto result : results) {
            Long spend = result.getSpend();
            Long view = result.getView();
            Long click = result.getClick();
            Long conversion = result.getConversion();
            Long purchase = result.getPurchase();

            result.setCampaignTotalIndicator(spend, view, click, conversion, purchase);
        }

        return results;
    }
  • 페이지 수정
    • 캠페인 관리 페이지 (소재 리스트) 에서 광고주 정보를 띄우고 있었으나 이를 삭제하고 캠페인 전체 실적 통계와 소재별 통계를 표시하도록 수정
  • 소재 실적 통계 기능 수정
    • 기존에는 단일 Dto로 반환을 해야 했기 때문에 null 값을 허용하지 않아 null 값을 0으로 처리하였으나 List로 반환하여 소재의 실적이 아예 없을 경우 0값으로 표시되는 것이 아닌 아예 실적 칸을 빈칸으로 뜨게끔 변경

2. 결과

  • 수정 전
  • 수정 후 (초기 조회 시 30일 간 통계로 적용)
  • 7일 간 통계 기능 적용 시

3. 미흡한 점 및 개선해야 할 부분

  • List로 가져오다 보니 통계 값이 아예 조회되지 않는 = 실적이 존재하지 않는 소재는 null로 처리되어 표시 자체가 되지 않음 (Left Outer Join을 했음에도)
    • QueryDsl에서 빈 객체를 별도로 표기하는 방법이 있는지 찾아볼 필요가 있다
  • 실적 리스트 - 실적 통계 리스트를 부득이하게 분리하였지만 추후에는 이를 한번에 구현하는 것이 좋을 듯 하다....
profile
공부했던 내용들을 모아둔 창고입니다.

0개의 댓글