java - 使用 Spring Data 按提取的日期、月份和年份聚合项目组

直截了当,我该怎么做:

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

用 Spring 数据

我已经尝试过这个和其他一些形式,但没有成功

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 中按日、月和年分组,否则我需要在代码中转换所有这些分组数据。

提前致谢

最佳答案

您遇到了 spring mongo 的限制,您可以在单个 $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" }
}}

当然,要在 spring-mongo 中使用这种结构,您需要一个聚合阶段操作的自定义实现,它可以采用定义的 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")
    );

由于自定义类从内置辅助方法使用的同一基本类中抽象出来,因此可以与它们一起使用,如图所示。

这里使用日期数学的基本过程是当你 $subtract 一个 BSON Date 对象来自另一个,那么结果是毫秒的差异,在这种情况下,来自仅提取毫秒值的纪元日期( Date(0) )。这使您可以根据一天中的毫秒数进行数学运算,以模 ( $mod ) 取整到当前日期值。

就像你最初尝试的那样,当你后来 $add 该毫秒值到 BSON 日期对象返回的值再次是 BSON 日期。因此,添加到表示 epoch 的对象会返回一个新的 Date 对象,但会四舍五入为当前日期。

这通常比通过 date aggregation operators 提取部分有用得多。 , 而且代码也更短一些,尤其是在你在这里做的调整 UTC 时间的时候。

虽然 $group 的构造这里比 spring mongo 试图避免的辅助函数更简洁,它最终比运行单独的 $project 更有效阶段转换您真正只需要在 $group 中的字段值无论如何都要上台。

https://stackoverflow.com/questions/32789189/

相关文章:

mongodb - 查询以匹配包含点的多边形

mongodb - 如何在 Meteor 服务器端做 mongo 组

angularjs - angularjs可以直接连接mongodb吗?

java - MongoDb BSON 以 UTC 时间存储日期

node.js - 关于 Mongoose 填充关系一个字符串字段

mongodb - 引用错误 : require is not defined in MongoDB

node.js - MongoDB Aggregate 中的 Mongoose Virtuals

mongodb - 如何在 MongoDB 中获取(或聚合)数组的不同键

mongodb - 如何在 MongoDB 的单个集合中查找文档之间的集合交集?

mongodb - 聚合来自两个数组的 $sum 值