Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 744
caseyhanley Avatar asked Jul 17 '14 18:07

caseyhanley


2 Answers

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.

like image 102
yass Avatar answered Sep 24 '22 04:09

yass


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.

like image 21
Goodzilla Avatar answered Sep 22 '22 04:09

Goodzilla