Specifying Mongo Query Parameters From Client Controller (MEAN.JS)

All we need is an easy explanation of the problem, so here it is.

I am building an application using MongoDB, Angular, Express, and Node (MEAN stack).

I used the MEAN.JS generator to scaffold my application.

I will use the articles module as a reference.

Suppose I have 7000 records in my articles collection, and each record has a date associated with it. It is inefficient to load all 7000 records into memory every time I load the page to view the records in a table and I am seeing terrible performance losses because of it. For this reason, I would only like to load records with a date in the range of (1 Month Ago) to (1 Year From Now) and display them in the table. I can currently do this with the following:

In my articles.client.controller.js:

$scope.find = function() {
        $articles = Articles.query();
};

…and in my articles.server.controller.js:

var now = new Date();
var aYearFromNow = new Date(now.getTime() + 86400000*365); //add a year
var aMonthAgo = new Date(now.getTime() - 86400000*30); //subtract roughly a month

exports.list = function(req, res) { Article.find().where('date').lt(aYearFromNow).gt(aMonthAgo).sort('-created').populate('user', 'displayName').exec(function(err, articles) {
        if (err) {
            return res.send(400, {
                message: getErrorMessage(err)
            });
        } else {
            res.jsonp(articles);
        }
    });
};

The problem is that this is not a dynamic way of doing things. In other words, I want the user to be able to specify how far back and how far forward they want to see.

How can I bind to variables (e.g. ‘aYearFromNow’ and ‘aMonthAgo’) in my client view that will change the query parameters in my server controller?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Another way is to just pass the search parameters in the query method, like this:

 $scope.searchart = function() {
    Articles.query({start:$scope.startDate, end:$scope.endDate}, function(articles) {
        $scope.articles = articles;
    });
};

and then at the server side controller, read your query string parameters like this:

exports.searcharticle = function(req, res) {
    Article.find().where('date').gt(req.query['start']).lt(req.query['end']).exec(function(err, articles) {
        if (err) {
            res.render('error', {
                status: 500
            });
        } else {
            res.jsonp(articles);
        }
    });
};

This way doesn’t require more routes or services.

Method 2

It’s probably not the cleanest way, but you can create a new service (or edit the current one to work with several parameters):

.factory('ArticlesService2', ['$resource',
    function($resource) {
        return $resource('articles/:param1/:param2', {
            param1: '',
            param2: ''
        }, {
            update: {
                method: 'PUT'
            }
        });
    }
]);

Then call it in your controller :

$scope.findWithParams = function() {
    $scope.article = ArticlesService2.query({
        param1: $scope.aYearFromNow,
        param2: $scope.aMonthAgo
    });
};

On the back-end, you’ll need to prepare a route :

app.route('/articles/:param1/:param2')
    .get(articles.listWithParams)

Add a function to your back-end controller :

exports.listWithParams = function(req, res) {
    Article.find()
    .where('date')
    .lt(req.params.param1)
    .gt(req.params.param2)
    .sort('-created').populate('user', 'displayName')
    .exec(function(err, articles) {
        if (err) {
            return res.send(400, {
                message: getErrorMessage(err)
            });
        } else {
            res.jsonp(articles);
        }
    });
};

Should work, haven’t tested it though.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply