Spring Mongo 每小时平均聚合

问题描述 投票:0回答:3

我一直在摸索如何以一种可以在应用程序中进一步使用它的方式聚合数据。

我想做的是获取原始数据

{
    "_id" : ObjectId("61e0898effba6778d05827e0"),
    "customId" : {
        "_id" : UUID("315fa023-f6a4-4d34-865c-dbe661e46cd1")
    },
    "viewers" : 1,
    "auditTime" : ISODate("2022-01-13T20:20:30.880Z"),
}
* lots 

进入

{
    "customId" : {
        "_id" : UUID("315fa023-f6a4-4d34-865c-dbe661e46cd1")
    },
    "averageViewers" : 5,
    "timePeriod" : ISODate("2022-01-13T20:10:00.00Z"),
}

我已经记录了时间段的匹配情况

        TypedAggregation<HistoricEntity> agg =
            Aggregation.newAggregation(HistoricEntity.class,
                                       Aggregation.match(Criteria.where("customId").is(channelId)),
                                       Aggregation.match(Criteria.where("auditTime").gte(start).andOperator(Criteria.where("auditTime").lte(end))),
                                       Aggregation.group("auditTime").avg("viewers").as("viewers")
            );

        AggregationResults<Map> aggregate = mongoTemplate.aggregate(agg, Map.class);

我认为理想的解决方案是使用 mongo atlas 聚合,我认为一旦解决这个问题就会很容易。

但我很失败。任何提示或技巧将非常感激

谢谢 亚当

spring mongodb spring-boot aggregate
3个回答
1
投票
ProjectionOperation convertAuditTimeToHourOp = Aggregation.project("customId", "viewers", "auditTime")
                .and(StringOperators.Substr.valueOf("auditTime").substring(0, 13))
                .as("auditHour");
                
GroupOperation countOp = Aggregation.group("customId", "auditHour").count().as("averageViewers");
        
ProjectionOperation convertAuditHourToDateOp = Aggregation.project("customId", "averageViewers", "auditHour")
                .and(StringOperators.Concat.valueOf("auditHour").concat(":00:00.000Z")).as("timePeriodString");
        
ProjectionOperation convertTimePeriodToDate = Aggregation.project("customId", "averageViewers", "timePeriodString")
                .and(DateFromString.fromStringOf("timePeriodString"))
                .as("timePeriod");

AggregationResults<Document> aggregate = mongoTemplate.aggregate(
                Aggregation.newAggregation(convertAuditTimeToHourOp, countOp, convertAuditHourToDateOp, convertTimePeriodToDate),
                HistoricEntity.class, 
                Document.class
);

List<Document> mappedResults = aggregate.getMappedResults();

1
投票

@indybee

这需要一点点摆弄。

我将计数更改为平均值以获得每小时的平均值(抱歉,这是一个狡猾的问题)

并使用 DateOperator 从中提取年月日小时

     ProjectionOperation convertAuditTimeToHourOp = Aggregation.project("channelId", "viewers", "auditTime")
            .and(DateOperators.dateOf("auditTime").toString("%Y-%m-%d-%H"))
            .as("auditHour");

        GroupOperation averageViewers = Aggregation.group("customId", "auditHour").avg("viewers").as("averageViewers");

    ProjectionOperation convertTimePeriodToDate = Aggregation.project("customId", "averageViewers", "auditHour")
            .and(DateOperators.DateFromString.fromStringOf("auditHour"))
            .as("timePeriod");

 ....

谢谢!


0
投票

一些改进用户DateTrunc无需再次投影:

ProjectionOperation convertAuditTimeToHourOp = Aggregation.project("channelId", "viewers", "auditTime")
                    .and(DateOperators.dateOf("auditTime").truncate("auditHour"))
                    .as("auditHour");
        
GroupOperation averageViewers = Aggregation.group("customId", "auditHour")
        .avg("viewers").as("averageViewers")
        .first("auditHour").as("auditHour")
        .first("customId").as("customId");
© www.soinside.com 2019 - 2024. All rights reserved.