LearnBoost/mongoose — pull request #1404 by njoyard (2013-03-28 09:13:19+00:00)
Title: Query-like aggregation (#1400)

Here is my take on more Query-like features for aggregation.

I added an Aggregate constructor with chainable methods; an Aggregate is created when calling Model.aggregate (but the previous syntax still works).

```js
// Previous syntax
Model.aggregate(
{ $group: { _id: null, maxAge: { $max: '$age' } } }
, { $project: { _id: 0, maxAge: 1 } }
, function (err, docs) { ... });

// New syntax
Model.aggregate() // instanceof Aggregate
.group({ _id: null, maxAge: { $max: '$age' } })
.select("-_id maxAge") // or .project({ _id: 0, maxAge: 1 })
.exec(function (err, docs) { ... }) // instanceof Promise

// Arbitrary operators
Model.aggregate()
.append(
{ $group: { _id: null, maxAge: { $max: '$age' } } }
, { $project: { _id: 0, maxAge: 1 } }
).exec(callback);
```

I created methods for each existing operator: group, project (with a query-like select alternative), skip, limit, geoNear, group, unwind, match and sort.

Everything has jsdoc and tests (in model.aggregate.test.js and aggregate.test.js) that all pass as of my last commit (https://github.com/njoyard/mongoose/commit/19ce3035b2c9954bf4bea31bd7bde9f024d03842).

Things that might be useful to add:
* Query-like where/in/lt/gt/... methods to create $match operators. Would be nice to find a way to reuse Query code without actually duplicating it.
* Casting aggregated docs to a matching Schema

Thanks for your feedback !