【问题标题】:Unable to compute average time无法计算平均时间
【发布时间】:2014-03-22 23:40:40
【问题描述】:

进入 MongoDB 3 天,我发现它不是很流畅。我只是想计算一个领域的平均时间,但我一直遇到各种各样的问题。

这是我的代码:

db.results.group({
     key:{"profile.Zend_Http_Client_Adapter_Socket::read==>fgets":{$exists:true}},
     initial: {count: 0, total:0},
     reduce: function(doc, out){ 
         out.count++; 
         out.total += doc."profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt";
     },
     finalize: function(out){
            out.avg = out.total/out.count;
     }
});

错误:

语法错误:意外字符串

以上是一个非常幼稚的错误,但我不明白为什么它会这样说,我能想到的唯一合理的原因是我在这里指定的键是引号,因此 Mongo 很困惑。

但是,这些键在我的集合中用引号引起来,所以我应该没有理由一直正确地得到这个语法错误?

示例文档:

{
    "_id" : ObjectId("532a2a986803faba658b456b"),
    "profile" : {
        "main()==>register_shutdown_function" : {
            "ct" : 1,
            "wt" : 13,
            "cpu" : 0,
            "mu" : 1568,
            "pmu" : 1000
        },
        "main()==>load::htdocs/index.php" : {
            "ct" : 1,
            "wt" : 17,
            "cpu" : 0,
            "mu" : 1736,
            "pmu" : 4296
},
        {"Zend_Http_Client_Adapter_Curl::write==>curl_exec" : {                                           
            "ct" : 3,
            "wt" : 54782314,
            "cpu" : 16001,
            "mu" : 83288,
            "pmu" : 49648
        }, ....

【问题讨论】:

  • 你能从收藏中发布一个示例文档吗?
  • 没用过Mongo,不过如果是Javascript的话应该是out.total += doc["profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt"];在 JS 中,对象键可以是字符串,但必须使用括号而不是点语法来查找它们。
  • @AnandJayabalan 刚刚做了。
  • 您最好使用aggregation framework。我正在输入一个示例查询,但 Neil 打败了我 :) 看看他的回答。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

根据评论,您的问题是形成有效的 JavaScript 之一。此外,您的“关键”价值似乎也不是您真正想要的。但是,您应该优先使用 aggregate 函数而不是使用“组”

db.results.aggregate([
    { "$match": {
        "$and": [
            { "profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt": {
                "$exists": true 
            }},
            { "profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt": { 
               "$not": { "$type": 2 }
            }}
        ]
    }},
    { "$group": {
        "_id": null,
        "total": { "$sum": 
            "$profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt"
        },
        "count": { "$sum": 1 }
    }},

    { "$project": {
        "_id": 0,
        "avg": { "$divide": [ "$total", "$count" ] }
   }}
])

聚合管道取代了之前引入的函数,例如groupdistinct。对于除了琐碎的操作之外的所有操作应该是您的首选。

它将运行得更快,因为这是在本机代码而不是 JavaScript 引擎中处理的。

另请参阅文档中的SQL to aggregation mapping chart

数据问题

您的样本不是很完整。为了解决所有问题,我必须将这样的文件放入:

{
    "profile": {
        "Zend_Http_Client_Adapter_Socket::read==>fgets": {                                           
            "ct" : 3,
            "wt" : 54782314,
            "cpu" : 16001,
            "mu" : 83288,
            "pmu" : 49648
        },
    }
}

您的文档示例中还有一些无效字段:

{
    "_id" : ObjectId("532a2a986803faba658b456b"),
    "profile" : {
        "main()==>register_shutdown_function" : {
            "ct" : 1,
            "wt" : 13,
            "cpu" : 0,
            "mu" : 1568,
            "pmu" : 1000
        },
        "main()==>load::htdocs/index.php" : { <-- Invalid
            "ct" : 1,
            "wt" : 17,
            "cpu" : 0,
            "mu" : 1736,
            "pmu" : 4296
},

因此该字段不能存在,因为它的字段名称中有 .,出于明显的子文档原因,这是不允许的。

【讨论】:

  • 谢谢,我从字面上复制粘贴了您的代码,上面写着:“异常:组聚合字段名称 '$count' 不能是操作员名称”
  • 好的,我把它拿出来了,但这次它给了我 "avg":null 作为答案
  • 删除了 $count 并用 count 替换它,给我一个 avg 为 0?那是因为看起来总数是 0
  • @ParijatKalia 是的,你当时是我输入的错误。已更正。
  • @ParijatKalia 参考见here。但是,您在 3 天后仍然做得很好来消化这个。
【解决方案2】:

@Neils 的回答让我找到了正确的解决方案:

db.results.aggregate([
    {
       $match: {
            "profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt": {
                "$exists": true
            }
        }
    },
    {
        $group: {
            "_id": null,
            "total": {
                $sum: "$profile.Zend_Http_Client_Adapter_Socket::read==>fgets.wt"
            },
            "count": {
                $sum: 1
            }
        }
    },
    {
        $project: {
            "_id": 0,
            "count": "$count",
            "avg": {
                $divide: [
                    "$total",
                    "$count"
                ]
            }
        }
    }
]);

【讨论】:

  • 只是一个建议......如果你想要平均值,你可以直接使用$avg运算符而不是使用$divide手动划分它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-02
  • 1970-01-01
  • 2020-11-24
相关资源
最近更新 更多