|
@@ -62,14 +62,14 @@ class MessageRecordService {
|
|
|
return await messageRecordModel_1.MessageRecord.findByIdAndUpdate(recordId, updateData, { new: true });
|
|
return await messageRecordModel_1.MessageRecord.findByIdAndUpdate(recordId, updateData, { new: true });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 获取整体消息推送统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 获取整体消息推送统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getOverallStatistics(startDate, endDate, strategyName) {
|
|
async getOverallStatistics(startDate, endDate, strategyName) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
|
return this.getStatisticsByGroup(matchConditions, []);
|
|
return this.getStatisticsByGroup(matchConditions, []);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按活动获取消息统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按活动获取消息统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByActivity(startDate, endDate) {
|
|
async getStatisticsByActivity(startDate, endDate) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate);
|
|
@@ -77,7 +77,7 @@ class MessageRecordService {
|
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { deliveredRate: -1 });
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { deliveredRate: -1 });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按策略获取消息统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按策略获取消息统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByStrategy(startDate, endDate, strategyName) {
|
|
async getStatisticsByStrategy(startDate, endDate, strategyName) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
@@ -85,7 +85,7 @@ class MessageRecordService {
|
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按模板获取消息统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按模板获取消息统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByTemplate(startDate, endDate, strategyName) {
|
|
async getStatisticsByTemplate(startDate, endDate, strategyName) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
@@ -93,7 +93,7 @@ class MessageRecordService {
|
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按国家代码获取消息统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按国家代码获取消息统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByCc(startDate, endDate, strategyName) {
|
|
async getStatisticsByCc(startDate, endDate, strategyName) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
@@ -101,7 +101,7 @@ class MessageRecordService {
|
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { totalRecords: -1 });
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { totalRecords: -1 });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按图片 URL 获取消息统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按图片 URL 获取消息统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByImage(startDate, endDate, strategyName) {
|
|
async getStatisticsByImage(startDate, endDate, strategyName) {
|
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
const matchConditions = this.buildMatchConditions(startDate, endDate, strategyName);
|
|
@@ -109,37 +109,37 @@ class MessageRecordService {
|
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
return this.getStatisticsByGroup(matchConditions, groupFields, { clickThroughRate: -1 });
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按时间维度的趋势分析,每日统计(含实际点击率)
|
|
|
|
|
|
|
+ * 按时间维度的趋势分析,每日统计(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailySentTrends(startDate, endDate, strategyName) {
|
|
async getDailySentTrends(startDate, endDate, strategyName) {
|
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, []);
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, []);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按国家代码和时间维度获取每日统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按国家代码和时间维度获取每日统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailyTrendsByCc(cc, startDate, endDate, strategyName) {
|
|
async getDailyTrendsByCc(cc, startDate, endDate, strategyName) {
|
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ cc }]);
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ cc }]);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按策略名称和时间维度获取每日统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按策略名称和时间维度获取每日统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailyTrendsByStrategy(strategyName, startDate, endDate) {
|
|
async getDailyTrendsByStrategy(strategyName, startDate, endDate) {
|
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ strategyName }]);
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ strategyName }]);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按模板ID和时间维度获取每日统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按模板ID和时间维度获取每日统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailyTrendsByTemplate(templateName, startDate, endDate, strategyName) {
|
|
async getDailyTrendsByTemplate(templateName, startDate, endDate, strategyName) {
|
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ templateName }]);
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ templateName }]);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按图片URL和时间维度获取每日统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按图片URL和时间维度获取每日统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailyTrendsByImage(image, startDate, endDate, strategyName) {
|
|
async getDailyTrendsByImage(image, startDate, endDate, strategyName) {
|
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ image }]);
|
|
return this.getDailyTrendsByDimensions(startDate, endDate, strategyName, [{ image }]);
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按多个维度获取消息推送统计数据(含实际点击率)
|
|
|
|
|
|
|
+ * 按多个维度获取消息推送统计数据(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getMultiDimensionalStatistics(filters) {
|
|
async getMultiDimensionalStatistics(filters) {
|
|
|
try {
|
|
try {
|
|
@@ -186,7 +186,7 @@ class MessageRecordService {
|
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
- // 计算比率并格式化输出(含实际点击率)
|
|
|
|
|
|
|
+ // 计算比率并格式化输出(含用户点击率)
|
|
|
pipeline.push({
|
|
pipeline.push({
|
|
|
$project: this.getStatisticsProjectFields(["date", "templateName", "strategyName", "cc", "image"]),
|
|
$project: this.getStatisticsProjectFields(["date", "templateName", "strategyName", "cc", "image"]),
|
|
|
});
|
|
});
|
|
@@ -285,7 +285,7 @@ class MessageRecordService {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 获取统计结果投影字段(含实际点击率)
|
|
|
|
|
|
|
+ * 获取统计结果投影字段(含用户点击率)
|
|
|
*/
|
|
*/
|
|
|
getStatisticsProjectFields(idFields) {
|
|
getStatisticsProjectFields(idFields) {
|
|
|
const project = { _id: 0 };
|
|
const project = { _id: 0 };
|
|
@@ -299,7 +299,7 @@ class MessageRecordService {
|
|
|
project[field] = `$_id.${field}`;
|
|
project[field] = `$_id.${field}`;
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
- // 统计字段:包含原有人次指标 + 新增人数指标 + 实际点击率
|
|
|
|
|
|
|
+ // 统计字段:包含原有人次指标 + 新增人数指标 + 用户点击率
|
|
|
return {
|
|
return {
|
|
|
...project,
|
|
...project,
|
|
|
// 原有人次指标
|
|
// 原有人次指标
|
|
@@ -329,7 +329,7 @@ class MessageRecordService {
|
|
|
tokenInvalidationRate: {
|
|
tokenInvalidationRate: {
|
|
|
$cond: [{ $eq: ["$totalRecords", 0] }, 0, { $divide: ["$failed", "$totalRecords"] }],
|
|
$cond: [{ $eq: ["$totalRecords", 0] }, 0, { $divide: ["$failed", "$totalRecords"] }],
|
|
|
},
|
|
},
|
|
|
- // 新增:实际点击率(人数维度)
|
|
|
|
|
|
|
+ // 新增:用户点击率(人数维度)
|
|
|
actualClickThroughRate: {
|
|
actualClickThroughRate: {
|
|
|
$cond: [
|
|
$cond: [
|
|
|
{ $eq: ["$displayedUsers", 0] }, // 避免除以0
|
|
{ $eq: ["$displayedUsers", 0] }, // 避免除以0
|
|
@@ -340,7 +340,7 @@ class MessageRecordService {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按分组获取统计数据的通用方法(支持实际点击率)
|
|
|
|
|
|
|
+ * 按分组获取统计数据的通用方法(支持用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getStatisticsByGroup(matchConditions, groupFields = [], sortOrder = { _id: 1 }) {
|
|
async getStatisticsByGroup(matchConditions, groupFields = [], sortOrder = { _id: 1 }) {
|
|
|
try {
|
|
try {
|
|
@@ -380,7 +380,7 @@ class MessageRecordService {
|
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
- // 计算比率并格式化输出(含实际点击率)
|
|
|
|
|
|
|
+ // 计算比率并格式化输出(含用户点击率)
|
|
|
pipeline.push({
|
|
pipeline.push({
|
|
|
$project: this.getStatisticsProjectFields(groupFields),
|
|
$project: this.getStatisticsProjectFields(groupFields),
|
|
|
});
|
|
});
|
|
@@ -395,7 +395,7 @@ class MessageRecordService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
/**
|
|
/**
|
|
|
- * 按维度获取每日趋势的通用方法(支持实际点击率)
|
|
|
|
|
|
|
+ * 按维度获取每日趋势的通用方法(支持用户点击率)
|
|
|
*/
|
|
*/
|
|
|
async getDailyTrendsByDimensions(startDate, endDate, strategyName, extraConditions = []) {
|
|
async getDailyTrendsByDimensions(startDate, endDate, strategyName, extraConditions = []) {
|
|
|
try {
|
|
try {
|
|
@@ -436,7 +436,7 @@ class MessageRecordService {
|
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
...this.getStatusAggregationFields(), // 包含人次+人数统计
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
- // 计算比率并格式化输出(含实际点击率)
|
|
|
|
|
|
|
+ // 计算比率并格式化输出(含用户点击率)
|
|
|
pipeline.push({
|
|
pipeline.push({
|
|
|
$project: {
|
|
$project: {
|
|
|
_id: 0,
|
|
_id: 0,
|