Pergunta

I am trying to operate on Date objects within an aggregation from nodejs with mongoose. My DB document has the following form:

{"__v" : 0,
"dob" : ISODate("1991-04-10T11:41:02.361Z"),
"gender" : "MALE",
...}

I am trying calculate the current age as follows, which works fine in robomongo and from the shell

db.p.aggregate([
{$project: { "age": {$divide: [{ $subtract: [ new ISODate(),  "$dob"  ] },31558464000]}}}
])

Output:

"result" : [ 
    {
        "age" : 23.00286577030492,
        "gender" : "MALE"
    }, 
    ...
]

But I cannot get it to work from within mongoose. If I use the same query, ISODate is not defined as stated here: ISODate is not defined

So as proposed I tried different variations of Date()

{$project: { "age": {$divide: [{ $subtract: [ new Date(),  "$dob"  ] }, 31558464000] }}}
RESULT: [MongoError: exception: cant $subtract a String from a Date]

{$project: {
   "age": {$divide: [{ $subtract: [ new Date(),  new Date("$dob")  ] }, 31558464000] },
   "dob2": { $subtract: [ new Date("$dob"), 1  ]  }, "dob": 1}}
RESULT: [ { _id: '10000000000000000000000b',
dob: '1991-04-10T11:41:02.361Z',
age: 44.27401739168928,                          <-- wrong age
dob2: Thu Jan 01 1970 00:59:59 GMT+0100 (CET) }, <-- wrong date
... ]

 {$project: {
   "age": {$divide: [{ $subtract: [ new Date(),  Date("$dob")  ] }, 31558464000] },
   "dob": 1}}
 RESULT: [MongoError: exception: cant $subtract a String from a Date]

If I try to convert the String to a date within the aggregation, it fails to convert correctly but outside of aggregate it works fine:

var dateISOString = "1991-04-10T11:41:02.361Z";
var dateTimeDate = new Date(startTimeISOString);
RESULT: Wed Apr 10 1991 13:41:02 GMT+0200 (CEST) 23.00290412198135  <-- correct Date

So I cannot use the direct reference $dob because it is treated as a String. I cannot use ISODate conversion because it is not defined and I cannot use new Date(), because the conversion is wrong within the aggregation framework. I have googled extensively, but could not find a solution to the problem. How can I either convert my ISODate string to the correct date or directly get a date in the first place without, leaving the aggregation. Help is much appreciated.

MongoDB: "version" : "2.4.9",
"sysInfo" : "Linux SMP Fri Nov 20 17:48:28 EST 2009 x86_64 BOOST_LIB_VERSION=1_49",

nodejs: v0.10.21

Edit after Neil's reply:

     function test( user, callback ) {
        var mongoose = require( 'mongoose' );

        mongoose.connect( 'mongodb://localhost:8080/11', function( ) {  } );


            var
                collection;
            if( err ) {
                callback( err );
            } else {
                collection = mongoose.connections[0].collection( 'aggregate' );

                        collection.aggregate([
                            { "$project": {
                                "_id": 0,
                                "this": { "$divide": [
                                    { "$subtract": [ new Date(), "$dob" ]},
                                    31558464000
                                ]}
                            }}
                        ], function( err, res ) {
                            console.warn( 'collection.doneCb.1', res, JSON.stringify( res ) );
                            callback( err, res );
                        } );

                        /*collection.aggregate( query, function( err, res ) {
                         console.warn( 'collection.doneCb.1', res, JSON.stringify( res ) );
                         callback( err, res );
                         } );*/
                    } );

                } );

            }

};

This produces:

{ [MongoError: exception: cant $subtract a String from a Date]
name: 'MongoError',
errmsg: 'exception: cant $subtract a String from a Date',
code: 16613,
ok: 0 }

Thanks!

Foi útil?

Solução

So just to clarify the output. ISODate is an internal function to MongoDB shell, or is otherwise provided in a driver function. But for JavaScript just use the Date() object constructor:

Given the data:

{ "date" : ISODate("1971-09-22T00:00:00Z") }

The following query:

db.birthdays.aggregate([
    { "$project": { 
        "_id": 0,
        "this": { "$divide": [
            { "$subtract": [ new Date(), "$date" ]}, 
            31558464000 
        ]} 
    }}
])

Produces:

{ "this" : 42.552055734461604 }

Even though I'm sorry to say it ;-)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top