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存储的数据是按照世界时存储的,因此进行分割操作时候需要对时间进行时区校正,因此需使用** a d d ∗ ∗ 加 上 时 区 差 8 小 时 ( 毫 秒 数 ) 才 能 得 到 正 确 的 数 据 , 最 后 一 步 便 是 利 用 ∗ ∗ add**加上时区差8小时(毫秒数)才能得到正确的数据,最后一步便是利用** add∗∗加上时区差8小时(毫秒数)才能得到正确的数据,最后一步便是利用∗∗group**进行分组了。细心的小伙伴可以会发现aggregate自带日期操作** y e a r , year, year,month, d a y O f M o n t h ∗ ∗ 用 于 获 取 年 , 月 , 日 , 会 想 着 通 过 这 三 个 参 数 来 拼 装 成 ∗ ∗ y y y y − M M − d d ∗ ∗ 日 期 格 式 , 可 惜 , f i d d i n g 之 前 也 是 这 么 操 作 的 , 只 是 最 后 发 现 a p p r e g a t e 并 解 析 不 了 , 故 在 此 使 用 了 ∗ ∗ dayOfMonth**用于获取年,月,日,会想着通过这三个参数来拼装成**yyyy-MM-dd**日期格式,可惜,fidding之前也是这么操作的,只是最后发现appregate并解析不了,故在此使用了** dayOfMonth∗∗用于获取年,月,日,会想着通过这三个参数来拼装成∗∗yyyy−MM−dd∗∗日期格式,可惜,fidding之前也是这么操作的,只是最后发现appregate并解析不了,故在此使用了∗∗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()