Java 使用Spring数据按提取的日期、月份和年份聚合项目组
直截了当地说,我如何做到这一点:Java 使用Spring数据按提取的日期、月份和年份聚合项目组,java,mongodb,mongodb-query,aggregation-framework,spring-mongo,Java,Mongodb,Mongodb Query,Aggregation Framework,Spring Mongo,直截了当地说,我如何做到这一点: group._id = { year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] } }; 使用spring
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
编写了,因为您发现目前也无法在\u id
中直接投影自定义命名字段
因此,您最好将这些都保留在$组中,并使用不同的方法将调整后的日期四舍五入到本地时间
因此,编写$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")
);
由于自定义类从内置helper方法使用的相同基本类中抽象出来,因此可以与它们一起使用,如图所示
在这里,日期数学的基本过程是这样的:当一个BSON date对象与另一个BSON date对象相比较时,结果是相差的毫秒数,在本例中是从历元日期(日期(0))中提取的毫秒值。这允许您进行数学运算,通过模()将一天中的毫秒数四舍五入到当前日期值
正如您最初尝试的那样,当您将该毫秒值转换为BSON Date对象时,返回的值仍然是BSON Date。因此,添加到表示历元的对象将返回一个新的日期对象,但四舍五入到当前日期
这通常比通过提取零件有用得多,而且编写代码的时间也要短一些,特别是在这里调整UTC时间时
尽管这里的$group
的构造比spring mongo试图避免的助手函数要简洁一些,最后,转换字段值要比运行单独的$project
阶段高效得多,而您实际上只需要在$group
阶段中转换字段值。非常感谢您的回答,也感谢您花时间解释mongo的限制和解决方法!我会尝试那种方法。这个答案太棒了!