0.需求
对多天的温、湿、照度的实时数据进行按日求平均值
1.数据格式
1.1 原始数据格式
{
"_id": "5edeec79a74c48f175774db1",
"_class": "com.wch.pf.base.common.aiot.entry.AppCallbackMessage",
"hubId": "161003C3",
"type": "Report",
"time": "2020-06-09T01:56:50.000Z",
"deviceId": "11119100001",
"data": {
"time": 1591667810000,
"humidity": 944,
"light": 89,
"temperature": 273
}
}
1.2 输出结果
{
"_id": "2020-06-08",
"light": 34.25,
"humidity": 916.5,
"temperature": 266.75
}
2.SQL实现
db.data.aiots.message.aggregate([
{
"$match": {
"deviceId": "11119100001" ,
time: {
$gte: ISODate("2020-06-08T12:36:33.000Z")
}
}
},
{
$project : {
//时区数据校准,8小时换算成毫秒数为8*60*60*1000=288000后分割成YYYY-MM-DD日期格式便于分组
day : {$substr: [{"$add":["$time", 28800000]}, 0, 10] },
"data": 1 // 设置原有data字段可用,用于计算总价
},
},
{
"$group": {
"_id": "$day",
"light": {$avg: "$data.light"},
"humidity": {$avg: "$data.humidity"},
"temperature": {$avg: "$data.temperature"}
}
}
]);
3.Java代码实现
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.match(criteria)
, Aggregation.project("data","time")
.andExpression("time + 28800000").substring(0,10).as("day")
, Aggregation.group("day")
.avg("data.temperature").as("temperature")
.avg("data.humidity").as("humidity")
.avg("data.light").as("light"));
AggregationResults<Map> aggregate = mongoTemplate.aggregate(aggregation, "data.aiots.message", Map.class);
代码解读
$match
用于匹配满足条件的文档,如同find函数。
$project
用于指示字段是否输出以及字段输出控制。
$substr
与$add
,一个是分割操作,另一个相加操作。不难发现我们的原始数据created_at字段是具体到秒,因此如果想根据日期进行分割的话,那么需要将created_at分割成我们想要的日期格式,这其中需要特别注意的是mongoodb存储的数据是按照世界时存储的,因此进行分割操作时候需要对时间进行时区校正,因此需使用**group**进行分组了。细心的小伙伴可以会发现aggregate自带日期操作**month,substr**分割方法。
$group
分组以及统计,其中**_id对应值便是我们所需分组的字段数据,totalPrice则是用$sum对同组数据的字段price进行求和,并将结果存放于totalPrice**中。
$sum
字段求和。
$sort
排序。
4.参考资料
mongoose聚合aggregate按日期分组计算
mongodb-Spring官方文档
Java Code Examples for org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation()