2017-06-22 101 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”组相同的基本概念基本适用。如前所述,“关键名称”对我来说似乎是一个更大的问题,可能会通过将它们移动到数组元素中的“值”来处理。但是,这取决于您是否在单个请求中写入多个邮件。但那是另一个练习,也许是另一个问题。 –