|
|
@@ -4,6 +4,23 @@ exports.MessageRecordService = void 0;
|
|
|
const messageRecordModel_1 = require("../models/messageRecordModel");
|
|
|
const clients_1 = require("./clients");
|
|
|
class MessageRecordService {
|
|
|
+ logPerf(endpoint, stage, durationMs, extra = {}) {
|
|
|
+ console.log(`[MessageStatsPerf] ${endpoint}:${stage}`, JSON.stringify({
|
|
|
+ endpoint,
|
|
|
+ stage,
|
|
|
+ durationMs,
|
|
|
+ ...extra,
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ resolveResultRows(result) {
|
|
|
+ if (Array.isArray(result)) {
|
|
|
+ return result.length;
|
|
|
+ }
|
|
|
+ if (result === null || result === undefined) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
/**
|
|
|
* 创建一条新的消息推送记录
|
|
|
* @param recordData 消息记录数据
|
|
|
@@ -171,11 +188,39 @@ class MessageRecordService {
|
|
|
* 用于首屏减少多次并行重查询。
|
|
|
*/
|
|
|
async getStatisticsSummary(startDate, endDate, strategyName, page = MessageRecordService.DEFAULT_STATS_PAGE, limit = MessageRecordService.DEFAULT_STATS_LIMIT) {
|
|
|
+ const summaryStartedAt = Date.now();
|
|
|
const [overall, dailyTrends, strategyStats] = await Promise.all([
|
|
|
- this.getOverallStatistics(startDate, endDate, strategyName),
|
|
|
- this.getDailySentTrends(startDate, endDate, strategyName),
|
|
|
- this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit),
|
|
|
+ (async () => {
|
|
|
+ const startedAt = Date.now();
|
|
|
+ const result = await this.getOverallStatistics(startDate, endDate, strategyName);
|
|
|
+ this.logPerf("summary", "overall", Date.now() - startedAt, {
|
|
|
+ resultRows: this.resolveResultRows(result),
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+ })(),
|
|
|
+ (async () => {
|
|
|
+ const startedAt = Date.now();
|
|
|
+ const result = await this.getDailySentTrends(startDate, endDate, strategyName);
|
|
|
+ this.logPerf("summary", "daily-trends", Date.now() - startedAt, {
|
|
|
+ resultRows: this.resolveResultRows(result),
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+ })(),
|
|
|
+ (async () => {
|
|
|
+ const startedAt = Date.now();
|
|
|
+ const result = await this.getStatisticsByStrategy(startDate, endDate, strategyName, page, limit);
|
|
|
+ this.logPerf("summary", "by-strategy", Date.now() - startedAt, {
|
|
|
+ resultRows: this.resolveResultRows(result),
|
|
|
+ page,
|
|
|
+ limit,
|
|
|
+ });
|
|
|
+ return result;
|
|
|
+ })(),
|
|
|
]);
|
|
|
+ this.logPerf("summary", "total", Date.now() - summaryStartedAt, {
|
|
|
+ dailyTrendRows: this.resolveResultRows(dailyTrends),
|
|
|
+ strategyRows: this.resolveResultRows(strategyStats),
|
|
|
+ });
|
|
|
return {
|
|
|
overall,
|
|
|
dailyTrends,
|
|
|
@@ -215,6 +260,7 @@ class MessageRecordService {
|
|
|
*/
|
|
|
async getMultiDimensionalStatistics(filters) {
|
|
|
try {
|
|
|
+ const startedAt = Date.now();
|
|
|
const pipeline = [];
|
|
|
// 构建匹配阶段
|
|
|
const matchStage = this.buildMatchConditions(filters.startDate, filters.endDate, filters.strategyName);
|
|
|
@@ -266,7 +312,16 @@ class MessageRecordService {
|
|
|
pipeline.push({
|
|
|
$sort: { date: 1, templateName: 1, cc: 1, image: 1 },
|
|
|
});
|
|
|
- return await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
|
|
|
+ const result = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
|
|
|
+ this.logPerf("multi-dimensional", "aggregate", Date.now() - startedAt, {
|
|
|
+ resultRows: this.resolveResultRows(result),
|
|
|
+ hasDateRange: Boolean(filters.startDate || filters.endDate),
|
|
|
+ hasStrategy: Boolean(filters.strategyName),
|
|
|
+ hasTemplate: Boolean(filters.templateName),
|
|
|
+ hasCc: Boolean(filters.cc),
|
|
|
+ hasImage: Boolean(filters.image),
|
|
|
+ });
|
|
|
+ return result;
|
|
|
}
|
|
|
catch (error) {
|
|
|
console.error("Error fetching multi-dimensional statistics:", error);
|
|
|
@@ -416,6 +471,7 @@ class MessageRecordService {
|
|
|
*/
|
|
|
async getStatisticsByGroup(matchConditions, groupFields = [], sortOrder = { _id: 1 }, page = MessageRecordService.DEFAULT_STATS_PAGE, limit = MessageRecordService.DEFAULT_STATS_LIMIT) {
|
|
|
try {
|
|
|
+ const startedAt = Date.now();
|
|
|
const pipeline = [];
|
|
|
// 添加匹配阶段
|
|
|
if (Object.keys(matchConditions).length > 0) {
|
|
|
@@ -479,7 +535,15 @@ class MessageRecordService {
|
|
|
pipeline.push({ $limit: safeLimit });
|
|
|
}
|
|
|
const results = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
|
|
|
- return groupFields.length === 0 ? results[0] : results;
|
|
|
+ const output = groupFields.length === 0 ? results[0] : results;
|
|
|
+ this.logPerf("statistics-by-group", "aggregate", Date.now() - startedAt, {
|
|
|
+ groupFields: groupFields.join(",") || "overall",
|
|
|
+ matchKeyCount: Object.keys(matchConditions || {}).length,
|
|
|
+ resultRows: this.resolveResultRows(output),
|
|
|
+ page,
|
|
|
+ limit,
|
|
|
+ });
|
|
|
+ return output;
|
|
|
}
|
|
|
catch (error) {
|
|
|
console.error("Error fetching statistics by group:", error);
|
|
|
@@ -491,6 +555,7 @@ class MessageRecordService {
|
|
|
*/
|
|
|
async getDailyTrendsByDimensions(startDate, endDate, strategyName, extraConditions = []) {
|
|
|
try {
|
|
|
+ const startedAt = Date.now();
|
|
|
const pipeline = [];
|
|
|
// 构建匹配条件
|
|
|
let matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
|
@@ -572,7 +637,14 @@ class MessageRecordService {
|
|
|
pipeline.push({
|
|
|
$sort: { date: -1 },
|
|
|
});
|
|
|
- return await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
|
|
|
+ const result = await messageRecordModel_1.MessageRecord.aggregate(pipeline).allowDiskUse(true);
|
|
|
+ this.logPerf("daily-trends", "aggregate", Date.now() - startedAt, {
|
|
|
+ hasDateRange: Boolean(startDate || endDate),
|
|
|
+ hasStrategy: Boolean(strategyName),
|
|
|
+ extraConditionCount: extraConditions.length,
|
|
|
+ resultRows: this.resolveResultRows(result),
|
|
|
+ });
|
|
|
+ return result;
|
|
|
}
|
|
|
catch (error) {
|
|
|
console.error("Error fetching daily trends:", error);
|