Parijat Kalia
Parijat Kalia

Reputation: 5085

Unable to compute average time

3 days old into MongoDB, and I am not finding it very fluid. I am simply trying to compute the average time for a field but I keep running into all sorts of problems.

Here is my code:

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;
     }
});

The error:

SyntaxError: Unexpected String

The above is a very childish error, but I can't understand why it would state this, the only plausible reason I can think of is that the keys I have specified here are in quotes hence Mongo is getting confused.

BUT, these keys ARE in quotes in my collection, so there should be no reason why I keep getting this syntax error right ?

Sample document:

{
    "_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
        }, ....

Upvotes: 0

Views: 453

Answers (2)

Neil Lunn
Neil Lunn

Reputation: 151072

As per the comment your problem is one of forming valid JavaScript. Also your "key" value would not seem to be what you really want. There is however the aggregate function that you should be favoring over the use of "group"

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

The aggregation pipeline sort of supercedes earlier introduced functions such as group and distinct. And for all but trivial operations should be your favored choice.

It will run much faster as well as this is processed in native code and not the JavaScript engine.

Also see the SQL to aggregation mapping chart in the documentation.

Problems With Data

Your sample is not very complete. To sort out all issues I have to put in a document like this:

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

Also your document example has some invalid fields in it:

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

So that field cannot exist as it has a . in the field name, which for obvious sub-document reasons is not allowed.

Upvotes: 2

Parijat Kalia
Parijat Kalia

Reputation: 5085

@Neils answer led me to the correct solution:

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

Upvotes: 0

Related Questions