I need to return the search results from Mongoose.findOne to variable
results = Lang.findOne({page: params.page,lang: params.lang, param: params.param}, function(err, lang) {
if( err || !lang) {
console.log("No translation!");
} else {
return lang.trans;
};
}
Is there a way to do this? I tried several hours to find a solution with async. functions and nothing ...
I also found articles where it was said that this is impossible, but is there any alternative for realize this?
It's really important to me because I need this to my multilingual project, I need to get the translation:
res.render('index',{titleGen : req.__({page:'home', lang:req.locale, param:'hello'})});
Here is the solution:
exports.getLang = getLang = function(params,callback){
console.log('received: '+params.page+' + '+params.lang+' + '+params.param);
Lang.findOne({page: params.page, lang: params.lang, param: params.param},function(err, lang){
if(err)
console.log(err)
else{
callback(lang.trans);
}
});
}
and routing:
router.get('/', function(req, res) {
req.__({page:'home', lang:req.locale, param:'hello'},function(text){
res.render('index',{titleGen : text });
})
});
Related
I'm new to node.js and I'm having a hard time trying to understand the concept of event-based async programming.
I'm implementing a restful API web service, so consider the following simple (synchronous!) API method addStuff(), which inserts stuff to an elasticsearch db:
var client = new elasticsearch.Client({ host: 'localhost:9200' });
function indexStuff(stuff) {
return client.index({
index: 'test_idx',
type: 'test',
id: stuff.id,
body: stuff
});
}
function addStuff(req, res, next) {
let stuff = processRequest(req);
indexStuff(stuff).then(
function (body) {
return true;
},
function (error) {
res.status(error.status).send({ message: error.message });
}
);
}
So far, so good.
Now during testing I wanted to avoid inserting already existing stuff to the db.
So I'd like to add something like:
function stuffAlreadyInDB(id) {
... // returns true/false
}
function addStuff(req, res, next) {
if (stuffAlreadyInDB(req.id))
{
res.status(409).send({ message: 'stuff with id ' + req.id + ' already in DB' });
return;
}
var stuff = processRequest(req);
...
}
Unfortunately, the call to the elasticsearch db is asyncronous, which means, I can't just return a boolean in a sync function. Instead, I have to refactor the whole shabang to something (argueably less easy to read) like this:
function getStuffByID(id) {
return client.get({
id: id,
index: 'test_idx',
type: 'test',
ignore: 404
});
}
function addStuff(req, res, next) {
getStuffByID(req.id).then(
function(resp) {
if (resp.found) {
res.status(409).send({ message: 'stuff with id ' + req.id + ' already in DB' });
return;
}
else {
var stuff = processRequest(req);
indexStuff(stuff).then(
function (body) {
res.writeHead(200, {'Content-Type': 'application/json' });
res.end();
},
function (error) {
res.status(error.status).send({ message: error.message });
}
);
}
},
function(error) {
res.status(error.status).send({ message: error.message });
}
);
}
At least, I haven't found any better solution. I tried to find out how to make the async call to the db a sync call, but basically everybody was saying: just don't do it.
So how am I supposed to do it right if I don't want to refactor everything and back-factor it when I finished testing and don't need this extra db check anymore?
Oh... and if you downvote my question: leave a comment why you do so.
Because I have the feeling that many people struggle with this issue, but I haven't found a satisfying answer yet.
you could use async\await syntax to make your code readable.
for example you could do this:
async function getStuffById(){
//return true or false; }
and in the "add stuff" function you could write:
if ( await getStuffById() ){
//do some more stuff }
please notice that you have to make "add stuff" async as well in order to use await syntax.
more on async \ await can be found here
So i am actually woking on a simple program with node.Js and i have an issue using async.waterfall :
I created a function in my user model that connect the user by accessing the database, here is the code :
exports.connection = function (login,password) {
async.waterfall([
function getLogin(callback){
usersModel.findOne({ login: login }, function (err, res) {
if (err){
callback(err,null);
return;
}
if(res != null ){
// test a matching password if the user is found we compare both passwords
var userReceived = res.items[0].login;
callback(null,userReceived);
}
});
},
function getPassword(userReceived, callback){
console.log(userReceived);
callback(null,'done')
}
], function(err){
if (err) {
console.error(err);
}
console.log('success');
});
}
Using node-inspector i figured out that the main issue(I think) is that when it enters the waterfall function it doesn't execute the callback function of findOne it literally skips this and directly jump to the getPassword function (which isn't executed too).
so if someone could help me figuring out what's the problem that would be nice since i'm on it for around two days now.
Thank you
EDIT:
After adding the different missing cases of tests(which was why the callback didn't worked) I have this connection function:
exports.connection = function (login,password) {
async.waterfall([
function getLogin(callback){
usersModel.findOne({ login: login }, function (err, res) {
console.log('login: ',res.login);
console.log('erreur: ',err);
if (err){
callback(err,null);
return;
}
if(!res)
{
console.log('getLogin - returned empty res');
callback('empty res');
}
if(res != null ){
// test a matching password if the user is found we compare both passwords
var userReceived = res;
callback(null,userReceived);
}
});
},
function getPassword(userReceived, callback){
console.log('login received :',userReceived.login);
var Ulogin = userReceived.login;
var Upassword = userReceived.password;
// function that compare the received password with the encrypted
//one
bcrypt.compare(password, Upassword, function(err, isMatch) {
if (err) {
console.log(err);
callback(err,null);
return;
}
else if (isMatch) {
console.log('Match', isMatch);
callback(null,isMatch);
}
else {
console.log('the password dont match', isMatch);
callback('pwd error',null);
}
});
},
], function(err){
if (err) {
console.error('unexpected error while connecting', err);
return false;
}
console.log('connected successfully');
return true;
});
}
And in my main file server.js i'm doing currently doing :
var connect = users.connection(login,password);
//the goal is to use the connect variable to know if the connection
//failed or not but it's 'undefined'
if(connect){
res.send('youyou connecté');
}
else {
res.send('youyou problem');
}
this absolutely don't work so i tried to use Q library but I have an error saying
"TypeError: Cannot read property 'apply' of undefined at Promise.apply"
here is the code using Q:
app.post('/signup', function (req, res) {
var login = req.body.login;
var password = req.body.password;
Q.fcall(users.connection(login,password))
.then(function (connect) {
if(connect){
res.send('connected');
}
else {
res.send('problem');
}
})
.catch(function (error) {
throw error;
})
.done();
});
but i am a little bit astonished i thought that by using async.waterfall() i told the function to wait until it received all the callbacks return so i don't understand why the connect variable is 'undefined'?
What I don't understand is - what was the flow exactly? did 'usersModel.findOne' get called?
What I see that is missing here in the getLogin function is a callback in the case that both the 'if' statement return false. in this case you'll get stuck in the first function and you won't advance to 'getPassword' function.
If this still doesn't work, please try executing the following code and report what was printed:
exports.connection = function (login,password) {
async.waterfall([
function getLogin(callback){
usersModel.findOne({ login: login }, function (err, res) {
if (err){
console.log('getLogin - error has occured');
callback(err,null);
return;
}
if(!res)
{
console.log('getLogin - returned empty res');
callback('empty res');
}
console.log('getLogin - result seems OK');
// test a matching password if the user is found we compare both passwords
var userReceived = res.items[0].login;
callback(null,userReceived);
}
});
},
function getPassword(userReceived, callback){
console.log('getPassword');
console.log(userReceived);
callback(null,'done')
}
], function(err){
if (err) {
console.error(err);
}
console.log('success');
});
}
I'm using Express and Handlebars to display a value set by the user and stored in the database.
Handlebars is set up to display the value "{{userMotto}}".
Express does the following:
function isUserAuthenticated(req, res, next) {
if (!req.user) {
res.render('index', {
user: req.user
});
} else {
currentUser = req.user.username;
userMottoCaught = queryDatabase("motto", currentUser);
next();
}
}
I want it to set the value of "userMottoCaught" to whatever it finds in the database. The query itself is this:
function queryDatabase(dbCollection, dbUID) {
this.dbCollection = dbCollection;
this.dbUID = dbUID;
return MongoClient.connectAsync(hiddenkeys.mongodbUri)
.then(function(db) {
return db.collection(dbCollection).findOneAsync({
_id: dbUID
});
})
.then(function(item) {
console.log("Found: ");
console.log(item);
return dbQueryResult;
})
.catch(function(err) {
//err
});
}
The problem is that I cannot for the life of me get the dbQueryResult out and return it to function queryDatabase itself. Probably because it's being returned to a sub function right now instead of the main function, I think. I highly suspect this can be easily resolved but I'm just at a loss on how to fix this. I am using Bluebird here to see if I could solve this with promises, but I'm not sure this is the right route either. I've also looked into callbacks but I cannot for the life of me figure out how to apply either concept to my code to solve my problem.
Later on when I render the page I do this to render it on the page:
router.get('/', isUserAuthenticated, function(req, res) {
res.render('dashboard', {
user: req.user,
userMotto: userMottoCaught
});
});
Currently this yields on the page: "Motto: [object Promise]", because I haven't returned the proper value to the main function.
Is there anyone out there with some wise words?
Cheers,
Dean
i think you need to make a callback here
function isUserAuthenticated(req, res, next) {
if (!req.user) {
res.render('index', {
user: req.user
});
} else {
currentUser = req.user.username;
userMottoCaught = queryDatabase("motto", currentUser,function(err,data){
userMottoCaught = data
next();
});
}
}
and the definition of queryDatabase should look like
function queryDatabase(dbCollection, dbUID,cb) {
this.dbCollection = dbCollection;
this.dbUID = dbUID;
return MongoClient.connectAsync(hiddenkeys.mongodbUri)
.then(function(db) {
return db.collection(dbCollection).findOneAsync({
_id: dbUID
});
})
.then(function(item) {
console.log("Found: ");
console.log(item);
dbQueryResult = JSON.stringify(item.motto);
cb(null,dbQueryResult)
})
.catch(function(err) {
//err
cb(err);
});
}
Im trying to create a function so i dont use the same code again and again but i keep getting internal error.I get the data and then i get the internal error so if i change something i need to refresh the page to be updated.I cant understand why i get the error.Here is the error
GET http://localhost:3000/api/pages 500 (Internal Server Error)
Object {data: "", status: 500, config: Object, statusText: "Internal Server Error"}
code:
function Get(some,that,res){
return some.find(function(err,that) {
if (!err) {
return res.send(that);
} else {
return res.send(500, err);
}
});
};
router.get('/pages', sessionCheck, function() {
Get(Page,pages,res);
});
UPDATE: i might doing something wrong so lets take it from the start.How can i create a function that do that so i dont reuse the same code again and again.
router.get('/pages', function(request, response) {
return Page.find(function(err, pages) {
if (!err) {
return response.send(pages);
} else {
return response.send(500, err);
}
});
});
and here is my full code
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Page= require('../models/page.js');
var bcrypt = require('bcrypt-nodejs');
function Get(some,that,response){
return some.find(function(that,err) {
if (!err) {
return response.send(that);
} else {
return response.send(500, err);
}
});
};
router.get('/pages', sessionCheck, function(request,response) {
Get(Page,pages,response);
});
router.METHOD will first call your function sessionCheck. You will then need to call next() within sessionCheck to call the next function, in which you are not defining any parameters (typically you would define req, res).
If you are using express your function call should probably be:
function someGetFunc(req, res, next)
You have res as the third parameter, so that might be the problem.
Now the Get function you have above is internal to an anonymous function that doesn't take in params, so what you are passing into it are either undefined or reference global scope variables.
ok i fixed it like that i shouldnt have left the function empty it required res,req
function Get(Some,that,res){
return Some.find(function(err,that) {
if (!err) {
return res.send(that);
} else {
return res.send(500, err);
}
});
};
router.get('/pages', sessionCheck,function(req,res) {
Get(Page,pages,res);
});
Okay, so in the past few days I started messing with Node (because I think I should learn something that is actually useful and might get me a job). Right now, I know how to serve pages, basic routing and such. Nice. But I want to learn how to query databases for information.
Right now, I'm trying to build an app that serves as a webcomic website. So, in theory, the application should query the database when I type in the url http://localhost:3000/comic/<comicid>
I have the following code in my app.js file:
router.get('/', function(req, res) {
var name = getName();
console.log(name); // this prints "undefined"
res.render('index', {
title: name,
year: date.getFullYear()
});
});
function getName(){
db.test.find({name: "Renato"}, function(err, objs){
var returnable_name;
if (objs.length == 1)
{
returnable_name = objs[0].name;
console.log(returnable_name); // this prints "Renato", as it should
return returnable_name;
}
});
}
With this setup I get console.log(getName()) to output "undefined" in the console, but I have no idea why it doesnt get the only element that the query can actually find in the database.
I have tried searching in SO and even for examples in Google, but no success.
How the hell am I supposed to get the parameter name from the object?
NodeJs is async. You need a callback or Promise.
router.get('/', function(req, res) {
var name = '';
getName(function(data){
name = data;
console.log(name);
res.render('index', {
title: name,
year: date.getFullYear()
});
});
});
function getName(callback){
db.test.find({name: "Renato"}, function(err, objs){
var returnable_name;
if (objs.length == 1)
{
returnable_name = objs[0].name;
console.log(returnable_name); // this prints "Renato", as it should
callback(returnable_name);
}
});
}
The getName function is making an asynchronous call to Mongo with db.test.find. You can see this by adding a console.log after the async function. Like this:
function getName(){
db.test.find({name: "Renato"}, function(err, objs){
var returnable_name;
if (objs.length == 1) {
returnable_name = objs[0].name;
console.log(returnable_name);
return returnable_name;
}
});
console.log('test'); // <!-- Here
}
In all likeliness, this will output:
test
Renato
You need to provide a callback to your getName function.
router.get('/', function(req, res) {
getName(function(err, name) {
res.render('index', {
title: name,
year: date.getFullYear()
});
})'
});
function getName(cb){
db.test.find({name: "Renato"}, function(err, objs){
if(err) cb(err);
var returnable_name;
if (objs.length == 1) {
returnable_name = objs[0].name;
return cb(null, returnable_name);
} else {
// Not sure what you want to do if there are no results
}
});
}