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()