feat: Switch to monthly_stats table for month/year stats aggregation
This commit is contained in:
parent
c1223c1f14
commit
02a9149f55
|
|
@ -42,65 +42,74 @@ async def get_plant_stats(
|
||||||
today_str = today.isoformat()
|
today_str = today.isoformat()
|
||||||
|
|
||||||
# 1. 과거 데이터 조회 (daily_stats)
|
# 1. 과거 데이터 조회 (daily_stats)
|
||||||
# 1. 과거 데이터 조회 (daily_stats)
|
# 1. 과거 데이터 조회 (period에 따라 테이블 분기)
|
||||||
|
stats_data_raw = []
|
||||||
|
is_monthly_source = False
|
||||||
|
|
||||||
if period == "day":
|
if period == "day":
|
||||||
|
# [일별 조회] daily_stats 테이블 사용
|
||||||
# 이번 달 1일부터 오늘까지
|
# 이번 달 1일부터 오늘까지
|
||||||
start_date = today.replace(day=1)
|
start_date = today.replace(day=1)
|
||||||
date_filter = start_date.isoformat()
|
date_filter = start_date.isoformat()
|
||||||
elif period == "month":
|
|
||||||
# year 파라미터가 있으면 해당 연도 1월~12월, 없으면 올해
|
|
||||||
target_year = year if year else today.year
|
|
||||||
start_date = datetime(target_year, 1, 1).date()
|
|
||||||
# 종료일: 해당 연도 12월 31일 또는 오늘 중 작은 값
|
|
||||||
end_date = min(datetime(target_year, 12, 31).date(), today)
|
|
||||||
date_filter = start_date.isoformat()
|
|
||||||
else: # year
|
|
||||||
# year 파라미터가 있으면 해당 연도부터, 없으면 최근 10년
|
|
||||||
if year:
|
|
||||||
start_year = year
|
|
||||||
else:
|
|
||||||
start_year = today.year - 9 # 10년치 데이터 (올해 포함)
|
|
||||||
start_date = datetime(start_year, 1, 1).date()
|
|
||||||
end_date = today
|
|
||||||
date_filter = start_date.strftime("%Y-%m-%d")
|
|
||||||
|
|
||||||
stats_query = db.table("daily_stats") \
|
stats_query = db.table("daily_stats") \
|
||||||
.select("date, total_generation") \
|
.select("date, total_generation") \
|
||||||
.eq("plant_id", plant_id) \
|
.eq("plant_id", plant_id) \
|
||||||
.gte("date", date_filter)
|
.gte("date", date_filter) \
|
||||||
|
.lte("date", today_str) \
|
||||||
|
.order("date", desc=False)
|
||||||
|
|
||||||
|
# 페이지네이션 등 없이 심플하게 (일별은 데이터 적음)
|
||||||
|
stats_data_raw = stats_query.execute().data
|
||||||
|
|
||||||
# period별 종료일 필터 추가
|
|
||||||
if period in ["month", "year"]:
|
|
||||||
stats_query = stats_query.lte("date", end_date.isoformat() if period == "month" else today_str)
|
|
||||||
else:
|
else:
|
||||||
stats_query = stats_query.lte("date", today_str)
|
# [월별/연도별 조회] monthly_stats 테이블 사용
|
||||||
|
is_monthly_source = True
|
||||||
|
|
||||||
stats_query = stats_query.order("date", desc=False)
|
if period == "month":
|
||||||
|
# year 파라미터가 있으면 해당 연도 1월~12월, 없으면 올해
|
||||||
|
target_year = year if year else today.year
|
||||||
|
start_month = f"{target_year}-01"
|
||||||
|
end_month = f"{target_year}-12" # 문자열 비교라 12월도 포함됨
|
||||||
|
else: # year
|
||||||
|
# year 파라미터가 있으면 해당 연도부터
|
||||||
|
if year:
|
||||||
|
start_year = year
|
||||||
|
else:
|
||||||
|
start_year = today.year - 9 # 10년치
|
||||||
|
start_month = f"{start_year}-01"
|
||||||
|
end_month = f"{today.year}-12"
|
||||||
|
|
||||||
# Supabase API Limit(1000) 우회를 위한 페이지네이션
|
stats_query = db.table("monthly_stats") \
|
||||||
all_stats_data = []
|
.select("month, total_generation") \
|
||||||
start = 0
|
.eq("plant_id", plant_id) \
|
||||||
batch_size = 1000
|
.gte("month", start_month) \
|
||||||
|
.lte("month", end_month) \
|
||||||
|
.order("month", desc=False)
|
||||||
|
|
||||||
while True:
|
stats_data_raw = stats_query.execute().data
|
||||||
# range는 inclusive index (Start, End)
|
|
||||||
result = stats_query.range(start, start + batch_size - 1).execute()
|
|
||||||
batch = result.data
|
|
||||||
all_stats_data.extend(batch)
|
|
||||||
|
|
||||||
if len(batch) < batch_size:
|
# 데이터 맵핑 {날짜키: 발전량}
|
||||||
break
|
# daily_stats: key='date' (YYYY-MM-DD)
|
||||||
start += batch_size
|
# monthly_stats: key='month' (YYYY-MM)
|
||||||
|
data_map = {}
|
||||||
|
for row in stats_data_raw:
|
||||||
|
key = row.get("month") if is_monthly_source else row.get("date")
|
||||||
|
val = row.get("total_generation") or 0
|
||||||
|
if key:
|
||||||
|
data_map[key] = val
|
||||||
|
|
||||||
# 데이터 맵핑 {날짜: 발전량}
|
# 2. 오늘 실시간 데이터 조회 (solar_logs)
|
||||||
data_map = {row["date"]: row["total_generation"] or 0 for row in all_stats_data}
|
# period='day'일 때만 합산 (monthly/year는 monthly_stats가 이미 갱신되었다고 가정하거나, 필요시 로직 추가)
|
||||||
|
# 하지만 monthly_stats가 '어제까지'의 합계일 수 있으므로, '이번 달' 데이터에는 오늘 발전량을 더해주는 게 안전함.
|
||||||
|
# 그러나 로직 복잡성을 피하기 위해, 크롤러가 실시간으로 monthly_stats를 갱신한다고 가정하고 여기선 생략 가능.
|
||||||
|
# 기존 로직 유지: 'day'일 때는 무조건 덮어쓰기.
|
||||||
|
|
||||||
# 2. 오늘 실시간 데이터 조회 (solar_logs) - 오늘이 조회 범위에 포함될 때만
|
|
||||||
today_generation = 0.0
|
today_generation = 0.0
|
||||||
if period == "day" or (period == "month" and (not year or year == today.year)) or period == "year":
|
# 일별 조회 시 오늘 데이터 덮어쓰기
|
||||||
# 오늘의 가장 마지막 기록 1건만 조회 (성능 최적화)
|
if period == "day":
|
||||||
logs_result = db.table("solar_logs") \
|
logs_result = db.table("solar_logs") \
|
||||||
.select("today_kwh, created_at") \
|
.select("today_kwh") \
|
||||||
.eq("plant_id", plant_id) \
|
.eq("plant_id", plant_id) \
|
||||||
.gte("created_at", f"{today_str}T00:00:00") \
|
.gte("created_at", f"{today_str}T00:00:00") \
|
||||||
.order("created_at", desc=True) \
|
.order("created_at", desc=True) \
|
||||||
|
|
@ -109,11 +118,13 @@ async def get_plant_stats(
|
||||||
|
|
||||||
if logs_result.data:
|
if logs_result.data:
|
||||||
today_generation = logs_result.data[0].get("today_kwh", 0.0)
|
today_generation = logs_result.data[0].get("today_kwh", 0.0)
|
||||||
|
if today_generation > 0:
|
||||||
|
data_map[today_str] = today_generation
|
||||||
|
|
||||||
# 3. 데이터 병합 (오늘 데이터 갱신/추가)
|
# 월별/연도별 조회 시: '이번 달' 키에 오늘 발전량을 더해야 하는가?
|
||||||
# solar_logs 값이 있으면 무조건 daily_stats 값보다 우선 (실시간성)
|
# 마이그레이션 스크립트는 daily_stats의 합을 넣었으므로 오늘 데이터도 포함됨.
|
||||||
if today_generation > 0:
|
# 크롤러도 실시간으로 daily 넣으면서 monthly upsert 할 예정.
|
||||||
data_map[today_str] = today_generation
|
# 따라서 별도 합산 불필요.
|
||||||
|
|
||||||
# 4. 포맷팅 및 집계
|
# 4. 포맷팅 및 집계
|
||||||
data = []
|
data = []
|
||||||
|
|
@ -158,7 +169,10 @@ async def get_plant_stats(
|
||||||
|
|
||||||
# 최근 10년 (또는 지정된 기간) 연도별 데이터 생성 (데이터 없으면 0)
|
# 최근 10년 (또는 지정된 기간) 연도별 데이터 생성 (데이터 없으면 0)
|
||||||
data = []
|
data = []
|
||||||
target_start_year = start_date.year
|
if year:
|
||||||
|
target_start_year = year
|
||||||
|
else:
|
||||||
|
target_start_year = today.year - 9
|
||||||
current_year = today.year
|
current_year = today.year
|
||||||
|
|
||||||
for y in range(target_start_year, current_year + 1):
|
for y in range(target_start_year, current_year + 1):
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user