带字符串时间戳的平均聚合

时间:2017-06-22 08:44:31

标签: python mongodb aggregation-framework pymongo

我在数据库中有如下记录:

{
    "_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()

我使用$ regex表达式查找与所选月份匹配的文档。

有没有办法使用这种方法进行平均操作?

我试着做点什么(下面)。我也尝试使用正则表达式进行聚合,但这是不可能的。

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 个答案:

答案 0 :(得分:1)

实际上你应该&#34;应该&#34;在这里修复时间戳字符串。但它们至少在词汇顺序中排在第二位。由于&#34; yyyy-dd-mm&#34; ISO Strings中固有的格式。

因此,由于它们具有固定长度,我们实际上可以使用聚合框架在服务器端聚合上聚合它们。

对五月份进行日期选择抽样:

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[]" }
  }}
])

这将得到每天的总数&#34;&#34;对于所选月份中的每一天。这依赖于字段的词汇值。相同的基本原则适用于此处的所有间隔。因此,您只需使用零值填充字符串,直到您想要选择的间隔。

同样适用于&#34;分组键&#34;这里,_id的值应该同样是直到所需间隔的子字符串。幸运的是,字符串格式为&#34;零填充&#34;所以小于"10"的值前面有"05"中的零。同样,这维持了&#34;范围&#34;的词汇顺序。

这就是你应该瞄准的目标,我认为你应该在这里选择你的字段,以及为范围选择生成时间戳字符串。

但是你肯定可以通过$group在实际值的[$substr][2]部分来表示你所需的间隔,而不需要为每个间隔迭代多个查询调用来获得一些东西。让数据库为你做。

你的&#34;键&#34;然而,这是另一个问题,因为它们不一致,你似乎总是在迭代可能的&#34;关键名称&#34;并为所有这些人执行单独的聚合。你可以把陈述更长一些,然后得到&#34;计数&#34;和&#34;总和&#34;每个使用$ifNull来确定何时递增。然后你会{&3}}&#34;&#34; $divide管道阶段获得最终&#34;平均值&#34;。

在不知道完整范围的情况下,最后一点有点复杂,而且并非完全在你的问题中。所以我会把这个留给你解决,或者问一个单独的问题。

  

N.B 此处$group从MongoDB 3.4开始实际上已弃用。替换运算符为$substr$substrBytes。此处使用的运算符现在被视为$substrCP的别名,它们在代码页处理方面有所不同,以考虑&#34; length&#34;记录在案。您应该使用适合您的代码页,但"timestamp"可能始终采用单字节编码。