2017-06-22 138 views
1

平均匯聚我在數據庫中的記錄如下:與字符串時間戳

{ 
    "_id" : ObjectId("592d4f43d69b643ac0cb9149"), 
    "timestamp" : "2017-03-01 17:09:00", 
    "Technique-Meteo_Direction moyenne du vent_Mean value wind direction[]" : 0.0, 
    "Technique-Meteo_Précipitations_Precipitation status[]" : 0.0, 
    "Technique-Meteo_Direction du vent_Wind direction[]" : 0.0 
} 

{ 
    "_id" : ObjectId("592d3a6cd69b643ac0cae395"), 
    "timestamp" : "2017-01-30 09:31:00", 
    "Technique-Electrique_Prises de Courant_Power1[W]" : 14.0, 
    "Technique-Electrique_Eclairage_Power2[W]" : 360.0, 
    "Technique-Electrique_Electroménager_Power3[W]" : 0.0, 
    "Technique-Electrique_VMC Aldes_Power4[W]" : 14.0, 
    "Technique-Electrique_VMC Unelvent_Power5[W]" : 8.0 

我的時間戳是一個簡單的字符串,我寧願不要因爲其他算法的變化量的觸摸。 但是,我想做一些平均操作。事實上,其他領域的傳感器名稱與他們的測量。我每分鐘都有一條記錄,我希望在一小時,一天或一個月內平均這些值。

就在,我創建一個查詢來算,每月現有值的數量對於一個場

countExistingPerMonth = client[page1.currentDB][page2.currentColl].find({"$and":[{"timestamp":{"$regex": regexExpression}}, {chosenSensor:{"$exists": True}}]}, temp_doc).count() 

我用正則表達式$表達式查找選擇一個月匹配的文檔。

有什麼辦法可以用我這種方法做我的平均操作嗎?

我試着做點什麼(下面)。我也嘗試使用正則表達式進行聚合,但這是不可能的。

self.sensorsStats = [] 
     for chosenSensor in self.chosenSensors: 
      countPerMonth = [] 
      years = [] 
      incre_year = int(page5.combo_startYear.get()) 
      if (incre_year<=int(page5.combo_endYear.get())): 
       while(incre_year!=(int(page5.combo_endYear.get())+1)): 
        years.append(str(incre_year)) 
        incre_year += 1 

      for year in years: 
       for month in ["01","02","03","04","05","06","07","08","09","10","11","12"]: 
        regexExpression = '^'+year+'-'+month+'-..' 

        test = client[page1.currentDB][page2.currentColl].aggregate([{"$match":{"timestamp":{"$regex": regexExpression}}}, {"$group":{"_id":chosenSensor, "average":{"$avg":{chosenSensor}}}}]) 

回答

1

現實你「應該」在這裏解決的時間戳字符串。但由於ISO字符串中固有的「yyyy-dd-mm」格式,它們至少處於「詞法順序」。

因此,由於它們具有固定長度,我們實際上可以使用服務器端聚合的聚合框架對它們進行聚合。

採樣五月的日期選擇:

cursor = client[page1.currentDB][page2.currentColl].aggregate([ 
    { "$match": { 
    "Technique-Meteo_Direction moyenne du vent_Mean value wind direction[]": 
     { "$exists": True }, 
    "timestamp": { 
     "$gte": "2017-05-01 00:00:00", "$lt": "2017-06-01 00:00:00" 
    } 
    }}, 
    { "$group": { 
    "_id": { 
     "$substr": [ "$timestamp", 0, 10 ] 
    }, 
    "average": 
     { "$avg": "$Technique-Meteo_Direction moyenne du vent_Mean value wind direction[]" } 
    }} 
]) 

這將得到「每日」的總的每一天於所選月份。這依賴於字段的詞彙價值。相同的基本原則適用於這裏的所有區間。因此,您只需填充零值的字符串,直到您希望選擇的時間間隔。

這裏的「分組鍵」也是如此,其中_id的值應該類似地是直到所需間隔的子串。幸運的是,字符串格式爲「零填充」,因此小於"10"的值在"05"之前爲零。這又保持了「範圍」的詞彙順序。

這就是你應該瞄準的目標,並且我認爲你應該在這裏選擇你的領域,並且爲範圍選擇生成時間戳字符串。

但是,您肯定可以通過在實際值中指定$group部分來表示您所需的時間間隔,並且不需要爲每個時間間隔簡單地迭代多個查詢調用,只需讓數據庫執行此操作即可您。然而

你的「鑰匙」是另一個問題,因爲它們並不一致,你似乎堅持通過可能「鍵名」迭代,併爲所有這些執行單獨的聚集。您可以使陳述更長,並獲得每個使用$ifNull的「計數」和「總和」以確定何時增加。然後你會在$divide之後的「$group」管道階段得到最終的「平均值」。

如果不知道整個範圍,最後一點有點複雜,並不完全在你的問題中。所以我會留給你解決,或者另外提出一個問題。

N.B這裏的$substr實際上是不贊成的MongoDB 3.4。替換運算符是和$substrCP。這裏使用的操作符現在被認爲是的別名,並且它們在代碼頁處理方面有所不同,因爲考慮到「長度」,如文檔所述。您應該使用適合您的代碼頁,但是無論如何,"timestamp"始終以單字節編碼。

+0

感謝您的回答。子串的想法顯然是我想要做的。因爲我沒有考慮這個問題,所以我試着用$ regex做類似的想法,例如每個值都是「2017-03」。但似乎$組不喜歡$正則表達式,或者我沒有正確地做,我不知道。但是,我終於決定在我看到它不會像我想象的那麼複雜之後,將我的時間戳(從字符串到日期格式)標準化。我一直關注你的最後一個提示,我想我完全不瞭解它,但我很快就會遇到相關問題。 –

+0

@Clément使用BSON Date是更好的選擇,我只是將它從答案中刪除,因爲您明確聲明不想轉換。但是,這很容易,因爲字符串應該很簡單地解析。雖然範圍選擇和「_id」組相同的基本概念基本適用。如前所述,「關鍵名稱」對我來說似乎是一個更大的問題,可能會通過將它們移動到數組元素中的「值」來處理。但是,這取決於您是否在單個請求中寫入多個郵件。但那是另一個練習,也許是另一個問題。 –