【问题标题】:Average Aggregation with String Timestamp带有字符串时间戳的平均聚合
【发布时间】:2017-06-22 08:44:31
【问题描述】:

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

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

【问题讨论】:

    标签: python mongodb aggregation-framework pymongo


    【解决方案1】:

    实际上,您“应该”在此处修复时间戳字符串。但由于 ISO 字符串中固有的“yyyy-dd-mm”格式,它们至少处于“词汇顺序”。

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

    为日期选择采样 5 月份:

    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"。这再次维护了“范围”的词汇顺序。

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

    但是您当然可以通过在实际值的 [$substr][2] 部分上使用$group 来指示您所需的间隔来获得一些东西,而无需简单地为每个间隔迭代多个查询调用,而只需让数据库为你做。

    但是,您的“键”是另一个问题,由于它们不一致,您似乎被困在遍历可能的“键名称”并为所有它们执行单独的聚合。您可以使语句更长,并使用$ifNull 获取每个语句的“计数”和“总和”以确定何时增加。然后你将$divide“在”$group 管道阶段之后得到最终的“平均值”。

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

    注意这里的 $substr 实际上在 MongoDB 3.4 中已被弃用。替换运算符是$substrBytes 和$substrCP。此处使用的运算符现在被认为是$substrBytes 的别名,并且它们在代码页处理方面有所不同,以考虑“长度”,如文档所述。您应该使用适合您的代码页,但很可能"timestamp" 始终采用单字节编码。

    【讨论】:

    • 感谢您的回答。子字符串的想法显然是我想要做的。因为我没有考虑过,所以我尝试了一个类似的想法,使用 $regex 来获得例如“2017-03”的每个值。但似乎 $group 不喜欢 $regex 或者我没有正确执行它,我不知道。然而,在我发现它并没有我想象的那么复杂之后,我最终决定规范化我的时间戳(从字符串到日期格式)。我一直在关注您的上一个提示,我想我并没有完全理解它,但我可能很快就会遇到相关问题。
    • @Clément 使用 BSON 日期是更好的选择,我只是将其排除在答案之外,因为您明确表示您不想转换。但是是的,这很容易,因为字符串应该非常简单地解析。范围选择和_id 组的基本概念基本相同。如前所述,“键名”对我来说似乎是一个更大的问题,通过将它们移动到数组元素中的“值”可能会更好地处理。但是,它确实取决于您是否在单个请求中写入多个。但这是另一个练习,也许是另一个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-10
    相关资源
    最近更新 更多