5

是直接的,我如何做到这一点:聚集项目组通过提取日,月,年和Spring数据

group._id = { 
    year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
    month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
    day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] } 
}; 

弹簧数据

我想这已经和其他一些形式和人不是全成

Aggregation aggregation = Aggregation.newAggregation(
       Aggregation.match(c), 
       Aggregation.project("programa", "custo", "duracao", "dataHora") 
        .andExpression("dataHora").minus(25200000).extractDayOfMonth().as("dia") 
        .andExpression("dataHora").minus(25200000).extractMonth().as("mes") 
        .andExpression("dataHora").minus(25200000).extractYear().as("ano"), 
       Aggregation.group("programa", "ano", "mes", "dia") 
        .count().as("count") 
        .sum("custo").as("valorTotal") 
        .sum("duracao").as("duracaoTotal") 
        .first("dataHora").as("dataHora"), 
       Aggregation.sort(Direction.ASC, "dataHora") 
     ); 

我需要按天,月和年在MongoDB中,否则我将需要所有这些分组的数据转换成代码。

在此先感谢

回答

5

您正在运行到春天蒙戈的,你可以在一个单一的$project阶段场计算做什么限制,而事实上你很可能已经编写为一个单独的$project,因为你会发现你目前无法直接在$group_id中投影自定义命名字段。

所以你会更好断保持这一切都在$group,以及使用四舍五入的调整日期以本地时间的不同方法。

更好的方式来写你因此$group是:

{ "$group": { 
    "_id": { 
    "programa": "$programa", 
    "dataHora": { 
     "$add": [ 
     { "$subtract": [ 
      { "$subtract": [{ "$subtract": ["$dataHora", new Date(0)] }, 25200000 ] }, 
      { "$mod": [ 
      { "$subtract": [{ "$subtract": ["$dataHora", new Date(0)] }, 25200000 ] }, 
      1000 * 60 * 60 * 24 
      ]} 
     ]}, 
     new Date(0) 
     ] 
    } 
    }, 
    "count": { "$sum": 1 }, 
    "valorTotal": { "$sum": "$custo" }, 
    "duracaoTotal": { "$sum": "$duracao" }, 
    "dataHora": { "$first": "$dataHora" } 
}} 

过程中使用这种与结构的弹簧蒙戈您需要的聚合阶段操作的自定义实现,可以采取一个定义DBObject

public class CustomGroupOperation implements AggregationOperation { 
    private DBObject operation; 

    public CustomGroupOperation (DBObject operation) { 
     this.operation = operation; 
    } 

    @Override 
    public DBObject toDBObject(AggregationOperationContext context) { 
     return context.getMappedObject(operation); 
    } 
} 

你那么环境中使用这样的:

Aggregation aggregation = Aggregation.newAggregation(
      Aggregation.match(c), 
      new CustomGroupOperation(
       new BasicDBObject("$group", 
        new BasicDBObject("_id", 
         new BasicDBObject("programa","$programa") 
          .append("dataHora", 
           new BasicDBObject("$add",Arrays.asList(
            new BasicDBObject("$subtract",Arrays.asList(
             new BasicDBObject("$subtract",Arrays.asList(
              new BasicDBObject("$subtract",Arrays.asList(
               "$dataHora", new Date(0) 
              )), 
              25200000 
             )), 
             new BasicDBObject("$mod",Arrays.asList(
              new BasicDBObject("$subtract",Arrays.asList(
               new BasicDBObject("$subtract",Arrays.asList(
                "$dataHora", new Date(0) 
               )), 
               25200000 
              )), 
              1000 * 60 * 60 * 24 
             )) 
            )), 
            new Date(0) 
           )) 
          ) 
        ) 
        .append("count",new BasicDBObject("$sum",1)) 
        .append("valorTotal",new BasicDBObject("$sum","$custo")) 
        .append("duracaoTotal",new BasicDBObject("$sum","$duracao")) 
        .append("dataHora",new BasicDBObject("$first","$dataHora")) 
       ) 
      ), 
      Aggregation.sort(Direction.ASC,"_id.dataHora") 
    ); 

由于通过内置的辅助方法,使用相同的基本类的自定义类摘要,它可以和他们一起使用,如图所示。

如何使用日期数学的基本过程在这里工作的是,当您从一个BSON Date对象$subtract结果是毫秒的差异,在这种情况下从纪元日期(日期(0))只是提取毫秒值。这允许你做数学题,通过毫秒数模($mod)舍入到当前的日期值在一天。

就像你最初试过的那样,当你接着$add那毫秒值到一个BSON Date对象时,返回值又是一个BSON Date。因此,向代表历元的对象添加一个新的Date对象,但四舍五入到当前日期。

这通常比通过date aggregation operators提取部件更有用,而且对代码的处理时间稍短一些,特别是根据您在此处调整UTC的时间时。

虽然这里的$group的敷设渠道是有点比春天蒙戈的辅助功能正试图避免更简洁,它到底比运行单独的$project阶段转变的字段值很多更有效,你无论如何,真的只想在$group阶段。

+0

非常感谢您的回答,并感谢您花这一次来解释mongo限制和解决方法!我会尝试这种方法 – Thiesen

+0

这个答案很有用! – nurgasemetey