Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongodb Aggregation Append method for optional $match pipeline operator

I'm using nodejs + mongoosejs with mongodb 2.6. I have a static function on a model that sums the value of all items in the collection. Each item is assigned to a project using a projectNo property. I need the static function to be able to give me the total for the collection, and if a projectNo argument is passed, add a $match pipeline operator to the aggregation. This will save me from having to make 2 static functions that essentially does the same thing.

To spice things up a bit I use bluebird promisifyAll method to make the aggregation framework return a promise.

my static function that sums the entire collection:

db.collection.aggregateAsync([ {$group:{_id: null, amount: { $sum: "$amount" }}} ])

my static function that sums only the records with a matching projectNo:

db.collection.aggregateAsync([ {$match: { projectNo: projectNo }}, {$group:{_id: null, amount: { $sum: "$amount" }}} ])

I really want to use the Aggregate.append method to append the $match pipeline only if a req.params.projectNo is included.

When I try to add it to the async aggregation it gets an error, which makes sense because its just a promise. If I try this:

db.collection.aggregateAsync([ {$group:{_id: null, amount: { $sum: "$amount" }}} ]).then(function(aggregate){ aggregate.append({$match: { projectNo: projectNo }}) })

I get an error, (append is undefined). How should I go about doing this? Or just live with the fact that I have two functions that do the same thing?

like image 348
Splitty Avatar asked Sep 28 '22 03:09

Splitty


1 Answers

I read the source code in mongodb to see exactly how to use the aggregate.append method. If you're building the aggregation using the chained methods, you can use append to add any pipeline operations.

So what I did instead is put the array of aggregation pipelines into an array. If there is a projectNo then I add the $match pipeline to the array using unshift(). I used unshift because you usually want the $match pipeline to first limit the number of records, then do the rest of the pipeline operations.

var pipeline = [{$group:{_id: null, amount: { $sum: "$amount" }}}];
if(req.params.projectNo){
    pipeline.unshift({$match: { projectNo: req.params.projectNo }});
}
db.collection.aggregateAsync(pipeline);

I usually make things way more complicated than I need to...

like image 102
Splitty Avatar answered Oct 19 '22 13:10

Splitty