Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing callback function to mongoose aggregate function

I am forming the query to be executed within aggregate() as follows:

query.$project = {};
query.$project.created_at = '$created_at';
query.$project.month = {};
query.$project.month.$month = currentMonth;
query.$match = {};
query.$match.month = currentMonth.getMonth() + 1;
query.$limit = 5;
query.$sort = {};
query.$sort.created_at = -1;
query.callback = function(err, result){
    // do something
};
console.dir(query);

But when i execute the following:

DataTable.aggregate(query);

I get this:

Error: Arguments must be aggregate pipeline operators
    at Aggregate.append (C:\myproject\node_modules\mongoose\lib\aggregate.js:87:11)
    at new Aggregate (C:\myproject\node_modules\mongoose\lib\aggregate.js:47:17)
    at Function.aggregate (C:\myproject\node_modules\mongoose\lib\model.js:1889:17)
    at C:\myproject\app\routes.js:179:23
    at C:\myproject\node_modules\async\lib\async.js:570:21
    at C:\myproject\node_modules\async\lib\async.js:249:17
    at C:\myproject\node_modules\async\lib\async.js:125:13

I have two question now:

  • Is there a better way to form this query.
  • And how do i specify callback function here.

Edit

I modified the above code as follows:

query.$project = {};
query.$project.created_at = '$created_at';
query.$project.month = {};
query.$project.month.$month = currentMonth;
query.$match = {};
query.$match.month = currentMonth.getMonth() + 1;
query.$limit = 5;
query.$sort = {};
query.$sort.created_at = -1;

But when i execute the following:

DataTable.aggregate(query, function(err, result){
    // do something
});
like image 929
jsbisht Avatar asked Feb 08 '15 04:02

jsbisht


1 Answers

Quoting Mongoose's documentation for aggregate,

Parameters:

  1. [...] <Object, Array> aggregation pipeline operator(s) or operator array

  2. [callback] <Function>

It is expecting you to pass

  1. an array of aggregation pipeline operators

    DataTable.aggregate([{
        $project: {
            created_at: '$created_at',
            month: {
                $month: currentMonth
            }
        }
    }, {
        $match: {
            month: currentMonth.getMonth() + 1
        }
    }, {
        $limit: 5
    }, {
        $sort: {
            created_at: -1
        }
    }], function(err, result) {
    
    });
    
  2. or multiple aggregation pipeline operators passed as individual arguments

    DataTable.aggregate({
        $project: {
            created_at: '$created_at',
            month: {
                $month: currentMonth
            }
        }
    }, {
        $match: {
            month: currentMonth.getMonth() + 1
        }
    }, {
        $limit: 5
    }, {
        $sort: {
            created_at: -1
        }
    }, function(err, result) {
    
    });
    

I would prefer the pipeline builder way,

DataTable.aggregate().project({
    created_at: '$created_at',
    month: {
        $month: currentMonth
    }
}).match({
    month: currentMonth.getMonth() + 1
}).limit(5).sort({
    created_at: -1
}).exec(function(err, result) {

});

Edit: If you prefer preparing individual items separately, then you can use an array object, like this

var query = [];

query.push({
    $project: {
        created_at: '$created_at',
        month: {
            $month: currentMonth
        }
    }
});

query.push({
    $match: {
        month: currentMonth.getMonth() + 1
    }
});

query.push({
    $limit: 5
});

query.push({
    $sort: {
        created_at: -1
    }
});

DataTable.aggregate(query, function(err, result) {

});

Or using the pipeline builder,

var aggregator = DataTable.aggregate();
...
aggregator = aggregator.project({...});
...
aggregator = aggregator.match({...});
...
aggregator = aggregator.limit(...);
...
aggregator = aggregator.sort(...);
...
aggregator.exec(function(err, result) {

});
like image 188
thefourtheye Avatar answered Nov 15 '22 20:11

thefourtheye