Search code examples
node.jsmongodbasynchronousmongooseecmascript-2016

Synchronous mongoose request


Is it possible to process a db.model.find() query inside of function context and retrieve a result without using callbacks and promises with mongoose library?

I need to get assured, if some user exists in process of running controller, so, I can't minimize current scope to callback due to large amount of same operations (for example, communication with database). Also I'm trying to realize MVC model in my project, so, I want to keep the helper libs (modules) in separated files. That's why I don't want to use any callbacks or promises - they will much times complicate everything even more then things already do.


For example, how should I rewrite the following code to be executed successfully (if it's actually possible) (you can ignore login model and controller - they are written to represent complicacy if to rewrite that code using callbacks):

user.js lib

var db = require('./lib/db');

class User{
    constructor(id){ //get user by id
        var result = db.models.user.findOne({_id: id}); //unsupported syntax in real :(
        if(!result || result._id != _id)
            return false;
        else{
            this.userInfo = result;

            return result;
        }

    }
}

module.exports = User;

login model

var user = require('./lib/user')
var model = {};

model.checkUserLogged(function(req){
    if(!req.user.id || req.user.id == undefined)
        return false;

    if(!(this.user = new user(req.user.id)))
        return false;
    else
        return true;
});

module.exports = model;

login controller

var proxy = require('express').router();

proxy.all('/login', function(req, res){

    var model = require('./models/login');

    if(!model.checkUserLogged()){
        console.log('User is not logged in!');
        res.render('unlogged', model);
    }else{
        console.log('User exists in database!');
        res.render('logged_in', model);
    }

});

Generator functions/yields, async/await (es2017), and everything et cetera can be used just to solve the problem without nesting.

Thx in advance.


Solution

  • There are two points wrong:

    • Mongoose methods can't be called synchronously (Anyway a call to a DB done synchronously is not a good idea at all).
    • Nor async/await nor generators can be used in the constructor of an ES6 Class. It is explained in this answer.

    If you don't want nested code an easy option could be to use async/await (currently available in Node.js using a flag, not recommended for production). Since Mongoose methods return promises they can be used with async/await.

    But as I said you can not do that in the constructor, so it has to be somewhere else.

    As an example you could do something like this:

    var proxy = require('express').router();
    var db = require('./lib/db');
    
    proxy.all('/login', async function(req, res){
        const result = await db.models.user.findOne({_id: req.user.id}).exec();
        if (!result) {
            console.log('User is not logged in!');
            return res.render('unlogged');
        }
        res.render('logged_in');
    });