|
|
@@ -343,7 +343,7 @@ class MessageRecordService {
|
|
|
$sum: {
|
|
|
$cond: [
|
|
|
{ $and: [{ $gte: ["$_id.status", 2] }, { $eq: ["$_id.inforeground", false] }] },
|
|
|
- { $size: "$uniqueUids" }, // 计算去重后的用户数
|
|
|
+ "$uniqueUsers", // 由上游分层聚合提前去重计数
|
|
|
0,
|
|
|
],
|
|
|
},
|
|
|
@@ -351,7 +351,7 @@ class MessageRecordService {
|
|
|
openedUsers: {
|
|
|
// 点击人数:至少点击1次的独立用户数
|
|
|
$sum: {
|
|
|
- $cond: [{ $eq: ["$_id.status", 3] }, { $size: "$uniqueUids" }, 0],
|
|
|
+ $cond: [{ $eq: ["$_id.status", 3] }, "$uniqueUsers", 0],
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
@@ -421,22 +421,36 @@ class MessageRecordService {
|
|
|
if (Object.keys(matchConditions).length > 0) {
|
|
|
pipeline.push({ $match: matchConditions });
|
|
|
}
|
|
|
- // 构建分组键
|
|
|
+ // 构建细粒度分组键(包含uid,先做去重基底)
|
|
|
const groupId = {};
|
|
|
groupFields.forEach((field) => {
|
|
|
groupId[field] = `$${field}`;
|
|
|
});
|
|
|
groupId.status = "$status";
|
|
|
groupId.inforeground = "$inforeground";
|
|
|
- // 第一阶段分组 - 收集唯一用户ID
|
|
|
+ groupId.uid = "$uid";
|
|
|
+ // 第一阶段分组 - 维度+状态+uid 聚合,避免使用 $addToSet 大数组
|
|
|
pipeline.push({
|
|
|
$group: {
|
|
|
_id: groupId,
|
|
|
- count: { $sum: 1 }, // 人次统计
|
|
|
- uniqueUids: { $addToSet: "$uid" }, // 收集该分组下的唯一用户
|
|
|
+ msgCount: { $sum: 1 },
|
|
|
},
|
|
|
});
|
|
|
- // 第二阶段分组 - 按主要维度汇总
|
|
|
+ // 第二阶段分组 - 收敛到维度+状态,保留人次统计和去重人数统计
|
|
|
+ const statusLevelGroupId = {};
|
|
|
+ groupFields.forEach((field) => {
|
|
|
+ statusLevelGroupId[field] = `$_id.${field}`;
|
|
|
+ });
|
|
|
+ statusLevelGroupId.status = "$_id.status";
|
|
|
+ statusLevelGroupId.inforeground = "$_id.inforeground";
|
|
|
+ pipeline.push({
|
|
|
+ $group: {
|
|
|
+ _id: statusLevelGroupId,
|
|
|
+ count: { $sum: "$msgCount" },
|
|
|
+ uniqueUsers: { $sum: 1 },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ // 第三阶段分组 - 按主要维度汇总
|
|
|
const mainGroupId = {};
|
|
|
groupFields.forEach((field) => {
|
|
|
mainGroupId[field] = `$_id.${field}`;
|
|
|
@@ -497,12 +511,19 @@ class MessageRecordService {
|
|
|
uid: "$uid", // 保留uid用于去重统计
|
|
|
},
|
|
|
});
|
|
|
- // 按日期、状态和前景标志分组 - 收集唯一用户
|
|
|
+ // 先按日期、状态、前景、uid 聚合,避免 $addToSet 占用大量内存
|
|
|
+ pipeline.push({
|
|
|
+ $group: {
|
|
|
+ _id: { date: "$date", status: "$status", inforeground: "$inforeground", uid: "$uid" },
|
|
|
+ msgCount: { $sum: 1 },
|
|
|
+ },
|
|
|
+ });
|
|
|
+ // 再收敛到日期+状态+前景,得到人次和去重人数
|
|
|
pipeline.push({
|
|
|
$group: {
|
|
|
- _id: { date: "$date", status: "$status", inforeground: "$inforeground" },
|
|
|
- count: { $sum: 1 }, // 人次统计
|
|
|
- uniqueUids: { $addToSet: "$uid" }, // 收集该分组下的唯一用户
|
|
|
+ _id: { date: "$_id.date", status: "$_id.status", inforeground: "$_id.inforeground" },
|
|
|
+ count: { $sum: "$msgCount" },
|
|
|
+ uniqueUsers: { $sum: 1 },
|
|
|
},
|
|
|
});
|
|
|
// 按日期汇总 - 计算人数统计
|