Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use the Mongoose query builder to just return an aggregation pipeline array and not run the query?

I am working locally - this would never be done on a live website. I built a node/express server that will accept a stringified aggregation pipeline for Mongo, and return the results to the browser:

app.get('/aggregate/:collection', function(req, res) {

    var queryObject = JSON.parse(req.param('q'));

    var recProvider = getProviderForTable(req.params.collection);
    recProvider.getCollection(function(err, collection) {

        collection.aggregate(queryObject, {}, function(err, data) {
            res.json(data);
        });
    });

});

This makes it convenient to do some quick queries in the browser where I am building data visualizations:

$.get(LOCAL_SERVER + '/aggregate/my_records?q=' + JSON.stringify(pipeline));

I almost started to build a query builder like Mongoose has, but just to construct the aggregation pipeline array. I am wondering if I can use Mongoose's query builder in the browser just to make the array, then use that to hit my express server for the data, as above?

I want to build a chainable object so eg...

pipeline()
    .where('value').gt(1000)
    .where('category').in([1, 2, 3])
    .sort('-date')
    .skip(100).limit(10);

...would return the aggregation pipeline:

[
    {
        $match: {
            value: {
                $gt: 1000
            },
            category: {
                $in: [1, 2, 3]
            }
        }
    },
    {
        $sort: {
            date: -1
        }
    },
    {
        $skip: 100,
        $limit: 10
    }
]
like image 793
Joe Beuckman Avatar asked Nov 12 '22 03:11

Joe Beuckman


1 Answers

Looking through the source, it looks like whenever you're using the aggregate() function, the pipeline is stored in a property called _pipeline.

Using your example, if you write an aggregation pipeline like this...

var myAggregation = Model  // "Model" should actually be the name of your model
    .aggregate()
    .match({ value: { $gt: 1000 } })
    .match({ category: { $in: [1, 2, 3] } })
    .sort('-date')
    .skip(100)
    .limit(10);

Then myAggregation._pipeline will look like this...

[ { '$match': { value: { $gt: 1000 } } },
  { '$match': { category: { $in: [1, 2, 3] } } },
  { '$sort': { date: -1 } },
  { '$skip': 100 },
  { '$limit': 10 } ]

I noticed, however, that you're using the where() function, which actually creates a Query in mongoose instead of an aggregation pipeline. If you're set on using where(), the conditions and options are set a little differently. Instead of myAggregation._pipeline, they will be split into myAggregation._conditions and myAggregation.options. They are not written exactly the same way, but perhaps you can do some transformation into the format you want.

like image 133
Travis Avatar answered Nov 15 '22 05:11

Travis