Skip to content

Commit cf9ce48

Browse files
feat: 用户统计支持传入时间单位 (#73)
feat: 用户统计支持传入时间单位 - 用户统计接口增加 dateUnit 参数 支持传入 hour / day / week / month / year ### 相关资料 - close https://guild.adventurer.tech/projects/1/tickets/47
1 parent 60c41d4 commit cf9ce48

File tree

3 files changed

+85
-4
lines changed

3 files changed

+85
-4
lines changed

openapi.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"hash": "0d281cd06010165c6b9979c2c30e2f98b9c6eb6cc5c49a1d2374ddd3397883e0",
2+
"hash": "a499cd3dde02dd82d308aa0d3fcd3f082c1ee0cb50da627a71c9257fa5083fc4",
33
"openapi": "3.0.0",
44
"paths": {
55
"/hello": {
@@ -6270,6 +6270,17 @@
62706270
"createdAt"
62716271
]
62726272
}
6273+
},
6274+
"dateUnit": {
6275+
"type": "string",
6276+
"description": "Date unit for time-based grouping when createdAt is in group",
6277+
"enum": [
6278+
"hour",
6279+
"day",
6280+
"week",
6281+
"month",
6282+
"year"
6283+
]
62736284
}
62746285
}
62756286
},

src/user/dto/aggregate.dto.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,26 @@ export enum GroupField {
1313
createdAt = 'createdAt',
1414
}
1515

16+
export enum DateUnit {
17+
hour = 'hour',
18+
day = 'day',
19+
week = 'week',
20+
month = 'month',
21+
year = 'year',
22+
}
23+
1624
export class AggregateUserDto {
1725
/**
1826
* The group by clause
1927
*/
2028
@IsOptional()
2129
@IsEnum(GroupField, { each: true })
2230
group?: GroupField[];
31+
32+
/**
33+
* Date unit for time-based grouping when createdAt is in group
34+
*/
35+
@IsOptional()
36+
@IsEnum(DateUnit)
37+
dateUnit?: DateUnit;
2338
}

src/user/user.service.ts

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { createHash, validateHash } from 'src/lib/crypt';
88
import { countTailZero, inferNumber } from 'src/lib/lang/number';
99
import { buildMongooseQuery, genAggGroupId, genSort, unWindGroupId } from 'src/mongo';
1010

11-
import { AggregateUserDto } from './dto/aggregate.dto';
11+
import { AggregateUserDto, DateUnit, GroupField } from './dto/aggregate.dto';
1212
import { CreateUserDto } from './dto/create-user.dto';
1313
import { ListUsersQuery } from './dto/list-users.dto';
1414
import { UpdateUserDto } from './dto/update-user.dto';
@@ -180,8 +180,23 @@ export class UserService {
180180
*/
181181
aggregate(query: ListUsersQuery, dto: AggregateUserDto): Promise<UserAggregateResult[]> {
182182
const { filter, offset, limit, sort } = buildMongooseQuery(wrapFilter(query));
183-
const { group = [] } = dto;
184-
const groupId = genAggGroupId(group);
183+
const { group = [], dateUnit = DateUnit.day } = dto;
184+
185+
// 处理时间字段分组
186+
let groupId: any = {};
187+
const hasCreatedAt = group.includes(GroupField.createdAt);
188+
189+
if (hasCreatedAt) {
190+
// 分离出非时间字段
191+
const nonTimeFields = group.filter((field) => field !== GroupField.createdAt);
192+
// 为时间字段生成特殊的分组ID
193+
groupId = {
194+
...genAggGroupId(nonTimeFields),
195+
createdAt: this.getDateGroupExpression(dateUnit),
196+
};
197+
} else {
198+
groupId = genAggGroupId(group);
199+
}
185200

186201
// 特殊字段需要先进行 $unwind
187202
const unwindFields = ['labels', 'groups', 'roles'];
@@ -218,4 +233,44 @@ export class UserService {
218233

219234
return this.userModel.aggregate(pipeline);
220235
}
236+
237+
private getDateGroupExpression(dateUnit: DateUnit) {
238+
const dateExpression = '$createdAt';
239+
240+
switch (dateUnit) {
241+
case DateUnit.hour:
242+
return {
243+
year: { $year: dateExpression },
244+
month: { $month: dateExpression },
245+
day: { $dayOfMonth: dateExpression },
246+
hour: { $hour: dateExpression },
247+
};
248+
case DateUnit.day:
249+
return {
250+
year: { $year: dateExpression },
251+
month: { $month: dateExpression },
252+
day: { $dayOfMonth: dateExpression },
253+
};
254+
case DateUnit.week:
255+
return {
256+
year: { $year: dateExpression },
257+
week: { $week: dateExpression },
258+
};
259+
case DateUnit.month:
260+
return {
261+
year: { $year: dateExpression },
262+
month: { $month: dateExpression },
263+
};
264+
case DateUnit.year:
265+
return {
266+
year: { $year: dateExpression },
267+
};
268+
default:
269+
return {
270+
year: { $year: dateExpression },
271+
month: { $month: dateExpression },
272+
day: { $dayOfMonth: dateExpression },
273+
};
274+
}
275+
}
221276
}

0 commit comments

Comments
 (0)