score:2

Accepted answer

you seem to just want the timestamp values returned from the result. there is indeed a simple way to do this in the aggregation framework without using the date aggregation operators. you can use basic "date math" instead, and with a trick that can be used to extract the "timestamp" value from the date object and manipulate it:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$subtract": [
                { "$subtract": [ "$time", new date("1970-01-01") ] },
                { "$mod": [
                    { "$subtract": [ "$time", new date("1970-01-01") ] },
                    1000 * 60 * 60 * 24    
                ]}
            ]
        },
        "avg": { "$avg": "$temp_c" }
    }}
])

so the basic "trick" there is that when subtract one date object from another ( or similar operation ) the result returned is a number for "milliseconds" of the time difference between the two. so by using the "epoch" date of "1970-01-01", you get the "epoch timestamp" value for the date object as a number.

then the basic date math is applied by subtracting from this value the modulo ( or remainder ) from the milliseconds in a day. this "rounds" the value to represent the "day" on which the entry is recorded.

i like posting the json because it parses everywhere, but in a more php way, then like this:

$collection->aggregate(array(
    array( '$group' => array(
        '_id' => array(
            '$subtract' => array(
                array( '$subtract' =>  array( 
                    '$time', new mongodate(strtotime("1970-01-01 00:00:00"))
                ) ),
                array(  '$mod' => array(
                    array( '$subtract' =>  array( 
                        '$time', new mongodate(strtotime("1970-01-01 00:00:00"))
                    ) ),
                    1000 * 60 * 60 * 24    
                ))
            )
        ),
        "avg" => array( '$avg' => '$temp_c' )
    ))
))

so that is a little cleaner than using the date aggregation operators to get to your intended result. of course this is still not "all the way" to how you want the data to be presented where you can use it in the client.

the real thing to do here is manipulate the result so that you get the output format you want. this is probably better suited to your server code doing the manipulation before you return the response, but if you have mongodb 2.6 or greater then it is "possible" to do this within the aggregation pipeline itself:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$subtract": [
                { "$subtract": [ "$time", new date("1970-01-01") ] },
                { "$mod": [
                    { "$subtract": [ "$time", new date("1970-01-01") ] },
                    1000 * 60 * 60 * 24    
                ]}
            ]
        },
        "avg": { "$avg": "$temp_c" }
    }},
    { "$group": {
        "_id": null,
        "data": {
            "$push": {
                "$map": {
                    "input": { "$literal": [ 1,2 ] },
                    "as": "el",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el", 1 ] },
                            "$$_id",
                            "$avg"
                        ]
                    }
                }
            }
        }
    }}
])

so this is pretty sneaky really. after the initial "grouping" is done to determine the averages for each day you get two fields in your result documents per day for _id and avg. what the $map operator does here is takes and array as input ( in this case, just a numbered template with a pair of values to identify position ) and processes each element to return an array equal to the elements present in the original.

the $cond operator here allows you to look at the value of the current element of that array and "swap it" with another value present in the current document. so for each document, the results contain something that is a paired array like:

[ 1409346800000, 12 ]

then all that happens is all results are pushed into a single document with a "data" array that appears as follows:

{ "_id": null, "data": [ [..,..], [..,..], (...) ] }

now your data element in that one result is an array of array pairs representing the points you want.

of course though, operators like $map are only available from mongodb 2.6 and onwards, so if you have that available then you can use them but otherwise just process the results in code with a similar "map" operation:

function my_combine($v) {
    return array($v["_id"],$v["avg"])
}

$newresult = array_map( "my_combine", $result )

so this really comes down to array manipulation from whichever way you approach it, but the date manipulation trick should also save you some work in obtaining the results as the expected timestamp values as well.


Related Query

More Query from same tag