Mongodb聚合查詢Spring實現

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

代碼解讀

  1. $match用於匹配滿足條件的文檔,如同find函數。

  2. $project用於指示字段是否輸出以及字段輸出控制。

  3. $substr$add,一個是分割操作,另一個相加操作。不難發現我們的原始數據created_at字段是具體到秒,因此如果想根據日期進行分割的話,那麼需要將created_at分割成我們想要的日期格式,這其中需要特別注意的是mongoodb存儲的數據是按照世界時存儲的,因此進行分割操作時候需要對時間進行時區校正,因此需使用**add8()便add**加上時區差8小時(毫秒數)才能得到正確的數據,最後一步便是利用**group**進行分組了。

    細心的小夥伴可以會發現aggregate自帶日期操作**year,year,month,dayOfMonthyyyyMMddfiddingappregate使dayOfMonth**用於獲取年,月,日,會想着通過這三個參數來拼裝成**yyyy-MM-dd**日期格式,可惜,fidding之前也是這麼操作的,只是最後發現appregate並解析不了,故在此使用了**substr**分割方法。

  4. $group分組以及統計,其中**_id對應值便是我們所需分組的字段數據,totalPrice則是用$sum對同組數據的字段price進行求和,並將結果存放於totalPrice**中。

  5. $sum字段求和。

  6. $sort排序。

4.參考資料

mongoose聚合aggregate按日期分組計算
mongodb-Spring官方文檔
Java Code Examples for org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章