|
|
@@ -0,0 +1,91 @@
|
|
|
+"use strict";
|
|
|
+var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
+ return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
|
+};
|
|
|
+Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
+exports.runBackfill = runBackfill;
|
|
|
+const dayjs_1 = __importDefault(require("dayjs"));
|
|
|
+const clients_1 = require("../services/clients");
|
|
|
+const mongoose_1 = __importDefault(require("mongoose"));
|
|
|
+const doneRateModel_1 = __importDefault(require("../models/doneRateModel"));
|
|
|
+// 导入 DoneRate 模型
|
|
|
+// ClickHouse 表名
|
|
|
+const CLICKHOUSE_EVENTS_TABLE = "events";
|
|
|
+// =========================================================================
|
|
|
+// !!! 必须修改这里以设置回填的起始日期 (YYYY-MM-DD 格式) !!!
|
|
|
+// 示例: 如果您的 tipCount 追踪是从 2024 年 1 月 1 日开始的,则设置为 "2024-01-01"
|
|
|
+const BACKFILL_START_DATE = "2025-01-03";
|
|
|
+/**
|
|
|
+ * 遍历指定日期范围,从 ClickHouse 提取 tipCount 并回填到 DoneRate 记录中。
|
|
|
+ * @returns Promise<string> - 返回回填结果的摘要信息。
|
|
|
+ */
|
|
|
+async function runBackfill() {
|
|
|
+ console.log(`[TipCount Backfill] Starting tipCount initialization for DoneRate model.`);
|
|
|
+ // 设置日期范围:从 BACKFILL_START_DATE 到昨天
|
|
|
+ let startDate = (0, dayjs_1.default)(BACKFILL_START_DATE).startOf("day");
|
|
|
+ const endDate = (0, dayjs_1.default)().subtract(1, "day").startOf("day");
|
|
|
+ if (!startDate.isValid() || startDate.isAfter(endDate)) {
|
|
|
+ const errorMsg = `[TipCount Backfill] Invalid start date ${BACKFILL_START_DATE} or date range is empty. Aborting.`;
|
|
|
+ console.error(errorMsg);
|
|
|
+ return errorMsg;
|
|
|
+ }
|
|
|
+ console.log(`[TipCount Backfill] Date Range: ${startDate.format("YYYY-MM-DD")} to ${endDate.format("YYYY-MM-DD")}`);
|
|
|
+ let totalDaysProcessed = 0;
|
|
|
+ let totalDoneRateUpdated = 0;
|
|
|
+ // 循环遍历历史数据中的每一天
|
|
|
+ for (let currentDay = startDate; currentDay.isBefore(endDate) || currentDay.isSame(endDate); currentDay = currentDay.add(1, "day")) {
|
|
|
+ const currentYYYYMMDD = currentDay.format("YYYYMMDD");
|
|
|
+ const currentStartString = currentDay.format("YYYY-MM-DD HH:mm:ss");
|
|
|
+ const currentEndString = currentDay.endOf("day").format("YYYY-MM-DD HH:mm:ss");
|
|
|
+ console.log(`\n--- [TipCount Backfill] Processing date: ${currentYYYYMMDD} ---`);
|
|
|
+ totalDaysProcessed++;
|
|
|
+ try {
|
|
|
+ // 1. 从 ClickHouse 中提取当天的 tipCount
|
|
|
+ const tipCountsQuery = `
|
|
|
+ SELECT
|
|
|
+ res,
|
|
|
+ count() AS tip_count
|
|
|
+ FROM ${CLICKHOUSE_EVENTS_TABLE}
|
|
|
+ WHERE event = 'color_tip'
|
|
|
+ AND time >= toDateTime('${currentStartString}')
|
|
|
+ AND time < toDateTime('${currentEndString}')
|
|
|
+ GROUP BY res
|
|
|
+ HAVING res IS NOT NULL
|
|
|
+ `;
|
|
|
+ const tipResults = await clients_1.clickhouseService.queryEvents(tipCountsQuery);
|
|
|
+ console.log(`[TipCount Backfill] Retrieved ${tipResults.length} records with 'color_tip' event.`);
|
|
|
+ if (tipResults.length === 0) {
|
|
|
+ // 如果当天没有 tip 事件,但可能存在 DoneRate 记录,我们仍然需要更新它们 (如果它们是 null 或 undefined)
|
|
|
+ // 但由于 DoneRateModel 默认 tipCount: 0,所以我们只需要处理有 tip 事件的记录。
|
|
|
+ console.log(`[TipCount Backfill] No 'color_tip' events found for ${currentYYYYMMDD}. Skipping MongoDB update.`);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // 2. 批量更新 MongoDB 中的 DoneRate 记录
|
|
|
+ const bulkOps = tipResults
|
|
|
+ .filter((row) => row.res && mongoose_1.default.Types.ObjectId.isValid(row.res)) // 过滤掉无效的 res ID
|
|
|
+ .map((row) => ({
|
|
|
+ updateOne: {
|
|
|
+ // 查找条件:日期 + 作品ID (唯一复合索引)
|
|
|
+ filter: { date: currentYYYYMMDD, res: new mongoose_1.default.Types.ObjectId(row.res) },
|
|
|
+ // 更新操作:设置 tipCount 字段
|
|
|
+ // 注意:我们只更新 tipCount,不影响 startCount 和 doneCount
|
|
|
+ update: { $set: { tipCount: row.tip_count } },
|
|
|
+ // 如果 DoneRate 记录不存在,则忽略。因为 DoneRate 记录通常由 color_start/color_done 事件创建。
|
|
|
+ upsert: false,
|
|
|
+ },
|
|
|
+ }));
|
|
|
+ if (bulkOps.length > 0) {
|
|
|
+ const updateResult = await doneRateModel_1.default.bulkWrite(bulkOps, { ordered: false });
|
|
|
+ const modifiedCount = updateResult.modifiedCount || 0;
|
|
|
+ totalDoneRateUpdated += modifiedCount;
|
|
|
+ console.log(`[TipCount Backfill] Successfully updated ${modifiedCount} DoneRate documents for ${currentYYYYMMDD}.`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (error) {
|
|
|
+ console.error(`[TipCount Backfill] Fatal error processing date ${currentYYYYMMDD}:`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const summary = `[TipCount Backfill] DoneRate tipCount backfill completed. Total days processed: ${totalDaysProcessed}. Total DoneRate documents updated: ${totalDoneRateUpdated}.`;
|
|
|
+ console.log(`\n${summary}`);
|
|
|
+ return summary;
|
|
|
+}
|