首页 > 解决方案 > 按时间间隔分组 spring-data-mongo

问题描述

以下是我的文档结构:

{
   "_id":"5c59c35d8610f702d00e6f70",
   "stationId":"2",
   "listenerId":"807",
   "streamId":"37",
   "userAgentId":"7",
   "botDefinitionId":"18",
   "ipAddress":"50.116.14.48",
   "startTime":"2018-02-06T12:51:59.000Z",
   "endTime":"2018-02-06T12:53:56.000Z",
   "listenLength":"117",
   "totalDataUsed":"1433582",
}

使用 spring data mongo 我想将它们分组到时间窗口中(比如说 15 分钟间隔)。我创建了以下工作查询:

{
   '_id':{
      'year':{
         '$year':'$startTime'
      },
      'week':{
         '$week':'$startTime'
      },
      'dayOfMonth':{
         '$dayOfMonth':'$startTime'
      },
      'month':{
         '$month':'$startTime'
      },
      'hour':{
         '$hour':'$startTime'
      },
      'interval':{
         '$subtract':[
            {
               '$minute':'$startTime'
            },
            {
               '$mod':[
                  {
                     '$minute':'$startTime'
                  },
                  15
               ]
            }
         ]
      }
   },
   'count':{
      '$sum':1
   }
}

然后返回给我以下文件:

_id:{
   year:2018   week:15   dayOfMonth:18   month:4   hour:18   interval:45
},
count:9

如何使用GroupOperation在 spring-data-mongo 中指定此聚合?

标签: mongodbspring-data-mongodb

解决方案


我能想到的一种方法是在 $project 阶段调用函数,而不是在 $group 阶段调用它们。

使用DateOperator类提取小时、分钟、年份等字段。然后将 SpEL andExpression用于您的区间字段:

andExpression("minute - minute % 15").as("interval")

这将使用小时、间隔、年份等字段重塑您的文档。然后将它们按间隔和您想要的其他字段分组。

Aggregation agg = Aggregation.newAggregation(

    Aggregation.project()
        .and(DateOperators.Minute.minute("$timestamp")).as("minute")
        .and(DateOperators.Hour.hour("$timestamp")).as("hour")
        .and(DateOperators.DayOfMonth.dayOfMonth("$timestamp")).as("dayOfMonth"),

    Aggregation.project("hour","dayOfMonth","minute")
        .andExpression("minute - minute % 15").as("interval"),

    Aggregation.group("hour","dayOfMonth","interval")
        .addToSet("hour").as("hour")
        .addToSet("dayOfMonth").as("dayOfMonth")
        .addToSet("interval").as("interval")
        .count().as("count")
);

List<QueryResult> result = mongoTemplate.aggregate(agg, "collection_name", QueryResult.class).getMappedResults();

推荐阅读