Spaces:
Running
Running
Optimize data fetching: remove date range query and per-agent DB queries for better performance
Browse files- src/lib/dataService.js +35 -56
src/lib/dataService.js
CHANGED
|
@@ -140,26 +140,39 @@ class DataService {
|
|
| 140 |
async _fetchAllFromRemote() {
|
| 141 |
// First, get the max date from DB to know what we're aiming for
|
| 142 |
let dbMaxDate = null
|
|
|
|
| 143 |
try {
|
| 144 |
-
const
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
}
|
|
|
|
| 153 |
} catch (e) {
|
| 154 |
-
console.error('[DataService] Error getting DB
|
| 155 |
}
|
| 156 |
|
|
|
|
|
|
|
|
|
|
| 157 |
const pageSize = 1000
|
| 158 |
let from = 0
|
| 159 |
-
const all = []
|
| 160 |
let pageCount = 0
|
| 161 |
-
|
| 162 |
-
|
| 163 |
while (true) {
|
| 164 |
const to = from + pageSize - 1
|
| 165 |
pageCount++
|
|
@@ -187,7 +200,7 @@ class DataService {
|
|
| 187 |
// Track the last date in this page
|
| 188 |
const pageDates = pageData.map(r => r && r.date).filter(Boolean).sort()
|
| 189 |
if (pageDates.length > 0) {
|
| 190 |
-
lastFetchedDate = pageDates[pageDates.length - 1]
|
| 191 |
console.log(`[DataService] Page ${pageCount}: ${pageData.length} rows, date range: ${pageDates[0]} to ${lastFetchedDate}`)
|
| 192 |
}
|
| 193 |
|
|
@@ -197,33 +210,29 @@ class DataService {
|
|
| 197 |
break
|
| 198 |
}
|
| 199 |
|
| 200 |
-
// Continue to next page - don't stop early based on date comparison
|
| 201 |
-
// because pagination with order('date', ascending: true) might have
|
| 202 |
-
// multiple pages with the same date, and we need to fetch all pages
|
| 203 |
from += pageSize
|
| 204 |
}
|
| 205 |
|
| 206 |
-
// Log the final date range
|
| 207 |
if (all.length > 0) {
|
| 208 |
const dates = all.map(r => r && r.date).filter(Boolean).sort()
|
| 209 |
const fetchedMinDate = dates[0]
|
| 210 |
const fetchedMaxDate = dates[dates.length - 1]
|
| 211 |
-
console.log(`[DataService] Total fetched: ${all.length} rows
|
| 212 |
console.log(`[DataService] Last 10 dates:`, dates.slice(-10))
|
| 213 |
|
| 214 |
-
// Verify we got the max date - if not, fetch missing data
|
| 215 |
if (dbMaxDate) {
|
| 216 |
const fetchedMaxDateStr = typeof fetchedMaxDate === 'string' ? fetchedMaxDate.split('T')[0] : fetchedMaxDate
|
| 217 |
const dbMaxDateStr = typeof dbMaxDate === 'string' ? dbMaxDate.split('T')[0] : dbMaxDate
|
| 218 |
console.log(`[DataService] Verification: DB max date = ${dbMaxDateStr}, Fetched max date = ${fetchedMaxDateStr}`)
|
| 219 |
|
| 220 |
if (fetchedMaxDateStr !== dbMaxDateStr && fetchedMaxDateStr < dbMaxDateStr) {
|
| 221 |
-
console.warn(`[DataService] Missing data detected! DB has ${dbMaxDateStr} but we
|
| 222 |
console.log(`[DataService] Fetching missing data from ${fetchedMaxDateStr} to ${dbMaxDateStr}...`)
|
| 223 |
|
| 224 |
-
// Fetch
|
| 225 |
-
|
| 226 |
-
const nextDay = new Date(fetchedMaxDateStr)
|
| 227 |
nextDay.setUTCDate(nextDay.getUTCDate() + 1)
|
| 228 |
const nextDayStr = nextDay.toISOString().split('T')[0]
|
| 229 |
|
|
@@ -236,13 +245,12 @@ class DataService {
|
|
| 236 |
|
| 237 |
if (!missingError && missingData && missingData.length > 0) {
|
| 238 |
console.log(`[DataService] Fetched ${missingData.length} missing rows`)
|
| 239 |
-
// Merge missing data, avoiding duplicates by id
|
| 240 |
const existingIds = new Set(all.map(r => r.id))
|
| 241 |
const newRows = missingData.filter(r => !existingIds.has(r.id))
|
| 242 |
all.push(...newRows)
|
| 243 |
-
console.log(`[DataService] Added ${newRows.length} new rows
|
| 244 |
|
| 245 |
-
// Re-sort
|
| 246 |
all.sort((a, b) => {
|
| 247 |
const dateA = typeof a.date === 'string' ? a.date.split('T')[0] : a.date
|
| 248 |
const dateB = typeof b.date === 'string' ? b.date.split('T')[0] : b.date
|
|
@@ -251,10 +259,6 @@ class DataService {
|
|
| 251 |
|
| 252 |
const finalDates = all.map(r => r && r.date).filter(Boolean).sort()
|
| 253 |
console.log(`[DataService] After fetching missing data: ${all.length} total rows, date range: ${finalDates[0]} to ${finalDates[finalDates.length - 1]}`)
|
| 254 |
-
} else if (missingError) {
|
| 255 |
-
console.error(`[DataService] Failed to fetch missing data:`, missingError)
|
| 256 |
-
} else {
|
| 257 |
-
console.warn(`[DataService] No missing data found (this might indicate a data inconsistency)`)
|
| 258 |
}
|
| 259 |
} else if (fetchedMaxDateStr === dbMaxDateStr) {
|
| 260 |
console.log(`[DataService] ✓ Successfully fetched all data up to ${dbMaxDateStr}`)
|
|
@@ -323,7 +327,7 @@ class DataService {
|
|
| 323 |
.sort()
|
| 324 |
const start_date = dates[0] || '-'
|
| 325 |
|
| 326 |
-
// 计算 end_date
|
| 327 |
let end_date = '-'
|
| 328 |
if (seqFiltered.length > 0) {
|
| 329 |
const lastRow = seqFiltered[seqFiltered.length - 1]
|
|
@@ -332,31 +336,6 @@ class DataService {
|
|
| 332 |
end_date = dates[dates.length - 1]
|
| 333 |
}
|
| 334 |
|
| 335 |
-
// 查询数据库获取该 agent 的最新日期,确保 end_date 是最新的
|
| 336 |
-
try {
|
| 337 |
-
const { data: agentMaxDateData, error: agentMaxDateError } = await supabase
|
| 338 |
-
.from('trading_decisions')
|
| 339 |
-
.select('date')
|
| 340 |
-
.eq('agent_name', row.agent_name)
|
| 341 |
-
.eq('asset', row.asset)
|
| 342 |
-
.eq('model', row.model)
|
| 343 |
-
.order('date', { ascending: false })
|
| 344 |
-
.limit(1)
|
| 345 |
-
|
| 346 |
-
if (!agentMaxDateError && agentMaxDateData && agentMaxDateData.length > 0) {
|
| 347 |
-
const dbAgentMaxDate = agentMaxDateData[0].date
|
| 348 |
-
const dbAgentMaxDateStr = typeof dbAgentMaxDate === 'string' ? dbAgentMaxDate.split('T')[0] : dbAgentMaxDate
|
| 349 |
-
|
| 350 |
-
// 如果数据库中的日期更新,使用数据库的日期
|
| 351 |
-
if (dbAgentMaxDateStr && (!end_date || end_date === '-' || dbAgentMaxDateStr > end_date)) {
|
| 352 |
-
console.log(`[DataService] STEP3.5 - ${row.agent_name}|${row.asset}|${row.model}: DB has newer date ${dbAgentMaxDateStr} than calculated ${end_date}, using DB date`)
|
| 353 |
-
end_date = dbAgentMaxDateStr
|
| 354 |
-
}
|
| 355 |
-
}
|
| 356 |
-
} catch (e) {
|
| 357 |
-
console.error(`[DataService] Error querying DB for agent max date:`, e)
|
| 358 |
-
}
|
| 359 |
-
|
| 360 |
console.log(`[DataService] STEP3 - ${row.agent_name}|${row.asset}|${row.model}: Final end_date = ${end_date}, dates array length = ${dates.length}, seqFiltered length = ${seqFiltered.length}`)
|
| 361 |
if (seqFiltered.length > 0) {
|
| 362 |
const lastRowDate = seqFiltered[seqFiltered.length - 1].dateNormalized || (typeof seqFiltered[seqFiltered.length - 1].date === 'string' ? seqFiltered[seqFiltered.length - 1].date.split('T')[0] : seqFiltered[seqFiltered.length - 1].date)
|
|
|
|
| 140 |
async _fetchAllFromRemote() {
|
| 141 |
// First, get the max date from DB to know what we're aiming for
|
| 142 |
let dbMaxDate = null
|
| 143 |
+
let dbMinDate = null
|
| 144 |
try {
|
| 145 |
+
const [minDateResult, maxDateResult] = await Promise.all([
|
| 146 |
+
supabase
|
| 147 |
+
.from('trading_decisions')
|
| 148 |
+
.select('date')
|
| 149 |
+
.order('date', { ascending: true })
|
| 150 |
+
.limit(1),
|
| 151 |
+
supabase
|
| 152 |
+
.from('trading_decisions')
|
| 153 |
+
.select('date')
|
| 154 |
+
.order('date', { ascending: false })
|
| 155 |
+
.limit(1)
|
| 156 |
+
])
|
| 157 |
+
|
| 158 |
+
if (!minDateResult.error && minDateResult.data && minDateResult.data.length > 0) {
|
| 159 |
+
dbMinDate = minDateResult.data[0].date
|
| 160 |
+
}
|
| 161 |
+
if (!maxDateResult.error && maxDateResult.data && maxDateResult.data.length > 0) {
|
| 162 |
+
dbMaxDate = maxDateResult.data[0].date
|
| 163 |
}
|
| 164 |
+
console.log(`[DataService] DB date range: min = ${dbMinDate}, max = ${dbMaxDate}`)
|
| 165 |
} catch (e) {
|
| 166 |
+
console.error('[DataService] Error getting DB date range:', e)
|
| 167 |
}
|
| 168 |
|
| 169 |
+
const all = []
|
| 170 |
+
|
| 171 |
+
// Fetch all data using pagination (faster than date range query)
|
| 172 |
const pageSize = 1000
|
| 173 |
let from = 0
|
|
|
|
| 174 |
let pageCount = 0
|
| 175 |
+
|
|
|
|
| 176 |
while (true) {
|
| 177 |
const to = from + pageSize - 1
|
| 178 |
pageCount++
|
|
|
|
| 200 |
// Track the last date in this page
|
| 201 |
const pageDates = pageData.map(r => r && r.date).filter(Boolean).sort()
|
| 202 |
if (pageDates.length > 0) {
|
| 203 |
+
const lastFetchedDate = pageDates[pageDates.length - 1]
|
| 204 |
console.log(`[DataService] Page ${pageCount}: ${pageData.length} rows, date range: ${pageDates[0]} to ${lastFetchedDate}`)
|
| 205 |
}
|
| 206 |
|
|
|
|
| 210 |
break
|
| 211 |
}
|
| 212 |
|
|
|
|
|
|
|
|
|
|
| 213 |
from += pageSize
|
| 214 |
}
|
| 215 |
|
| 216 |
+
// Log the final date range and verify - if missing data, fetch it
|
| 217 |
if (all.length > 0) {
|
| 218 |
const dates = all.map(r => r && r.date).filter(Boolean).sort()
|
| 219 |
const fetchedMinDate = dates[0]
|
| 220 |
const fetchedMaxDate = dates[dates.length - 1]
|
| 221 |
+
console.log(`[DataService] Total fetched: ${all.length} rows, date range: ${fetchedMinDate} to ${fetchedMaxDate}`)
|
| 222 |
console.log(`[DataService] Last 10 dates:`, dates.slice(-10))
|
| 223 |
|
| 224 |
+
// Verify we got the max date - if not, fetch missing data
|
| 225 |
if (dbMaxDate) {
|
| 226 |
const fetchedMaxDateStr = typeof fetchedMaxDate === 'string' ? fetchedMaxDate.split('T')[0] : fetchedMaxDate
|
| 227 |
const dbMaxDateStr = typeof dbMaxDate === 'string' ? dbMaxDate.split('T')[0] : dbMaxDate
|
| 228 |
console.log(`[DataService] Verification: DB max date = ${dbMaxDateStr}, Fetched max date = ${fetchedMaxDateStr}`)
|
| 229 |
|
| 230 |
if (fetchedMaxDateStr !== dbMaxDateStr && fetchedMaxDateStr < dbMaxDateStr) {
|
| 231 |
+
console.warn(`[DataService] Missing data detected! DB has ${dbMaxDateStr} but we fetched up to ${fetchedMaxDateStr}`)
|
| 232 |
console.log(`[DataService] Fetching missing data from ${fetchedMaxDateStr} to ${dbMaxDateStr}...`)
|
| 233 |
|
| 234 |
+
// Fetch missing data by date range
|
| 235 |
+
const nextDay = new Date(fetchedMaxDateStr + 'T00:00:00.000Z')
|
|
|
|
| 236 |
nextDay.setUTCDate(nextDay.getUTCDate() + 1)
|
| 237 |
const nextDayStr = nextDay.toISOString().split('T')[0]
|
| 238 |
|
|
|
|
| 245 |
|
| 246 |
if (!missingError && missingData && missingData.length > 0) {
|
| 247 |
console.log(`[DataService] Fetched ${missingData.length} missing rows`)
|
|
|
|
| 248 |
const existingIds = new Set(all.map(r => r.id))
|
| 249 |
const newRows = missingData.filter(r => !existingIds.has(r.id))
|
| 250 |
all.push(...newRows)
|
| 251 |
+
console.log(`[DataService] Added ${newRows.length} new rows`)
|
| 252 |
|
| 253 |
+
// Re-sort
|
| 254 |
all.sort((a, b) => {
|
| 255 |
const dateA = typeof a.date === 'string' ? a.date.split('T')[0] : a.date
|
| 256 |
const dateB = typeof b.date === 'string' ? b.date.split('T')[0] : b.date
|
|
|
|
| 259 |
|
| 260 |
const finalDates = all.map(r => r && r.date).filter(Boolean).sort()
|
| 261 |
console.log(`[DataService] After fetching missing data: ${all.length} total rows, date range: ${finalDates[0]} to ${finalDates[finalDates.length - 1]}`)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
}
|
| 263 |
} else if (fetchedMaxDateStr === dbMaxDateStr) {
|
| 264 |
console.log(`[DataService] ✓ Successfully fetched all data up to ${dbMaxDateStr}`)
|
|
|
|
| 327 |
.sort()
|
| 328 |
const start_date = dates[0] || '-'
|
| 329 |
|
| 330 |
+
// 计算 end_date:从已获取的数据中提取,因为数据已经完整
|
| 331 |
let end_date = '-'
|
| 332 |
if (seqFiltered.length > 0) {
|
| 333 |
const lastRow = seqFiltered[seqFiltered.length - 1]
|
|
|
|
| 336 |
end_date = dates[dates.length - 1]
|
| 337 |
}
|
| 338 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 339 |
console.log(`[DataService] STEP3 - ${row.agent_name}|${row.asset}|${row.model}: Final end_date = ${end_date}, dates array length = ${dates.length}, seqFiltered length = ${seqFiltered.length}`)
|
| 340 |
if (seqFiltered.length > 0) {
|
| 341 |
const lastRowDate = seqFiltered[seqFiltered.length - 1].dateNormalized || (typeof seqFiltered[seqFiltered.length - 1].date === 'string' ? seqFiltered[seqFiltered.length - 1].date.split('T')[0] : seqFiltered[seqFiltered.length - 1].date)
|