Function that calls function containing async query to mongodb.find [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
Is there a way to call function that contains mongoose query inside other function, so other function will work properly?
My first function containing mongoose query:
getUserTags = (id) => {
User.findById(id)
.exec( (error, user) => {
if (error) {
return next(error);
} else {
return user;
}
})
}
and my functions that needs to call that first function:
userTagToBookTagValues = (id) => {
const user = getUserTags(id);
//I NEED THIS PART TO WORK AFTER getting data from getUserTags
console.log(user);
user.tags.forEach(tag => {
console.log(tag)
});
}
Is there a way so it works properly and user in second function will not be undefined?

You maybe need to return User.findById?
Like so:
getUserTags = (id) => {
return User.findById(id)
.exec( (error, user) => {
if (error) {
return next(error);
} else {
return user;
}
})
}

As I understand .exec() do not return anything, so using .then gives error.
However if rewritten like this, it works perfectly:
getUserTags = (id) => {
return User.findById(id)
}
userTagToBookTagValues = (id) => {
const user = getUserTags(id).then((user) => {
user.tags.forEach(tag => {
console.log(tag)
});
}) ;
}

findById is an asynchronous method.
If your node version greater then 8
getUserTags = id => User.findById(id).exec();
userTagToBookTagValues = async (id) => {
try {
const user = await getUserTags(id);
user.tags.forEach(tag => {
console.log(tag)
});
} catch (err) {
next(err);
}
}
Or you can use then method after calling getUserTags function.
For more information about of asnc methods:
Medium

Related

TypeError: query.findAll is not a function node js mysql

i am trying to pass the sql query parameters to data access js file. i have imported the function in current file, but still am getting the below error.
current file
const tcount = async (value) => {
const sql = 'trainingcount';
const result = await query.findAll(sql);
return result;
}
data access file
const query = (results) => {
findAll: async (sql, result) => {
connection.query(`SELECT * FROM trainingcount`, (err, rows) => {
if (err) {
return results(null, err);
} else {
return results(rows);
}
});
};
};
export { query };
(node:11132) UnhandledPromiseRejectionWarning: TypeError:
query.findAll is not a function
EDIT: Check #rid solutions on the comments for the specific problem of calling the proper function. My answer solves a different problem in OP code.
you call return inside the callback function, so you are returning THAT function, not findAll. You need to return a Promise:
const query = (results) => {
findAll: (sql, result) => {
return new Promise((resolve, reject) => {
connection.query(`SELECT * FROM trainingcount`, (err, rows) => {
if (err) {
reject(err);
} else {
resolve(rows);
}
});
});
};
};
export { query };

getting undefined for a function used in another function [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I'm getting the required result from console.log in getuser(), but I'm getting undefined when used it in another function
let getuser = (id) => {
user.findById(id, (err, user) => {
if (err || !user) {
return "wrong user id";
} else {
let { name, _id } = user;
console.log(JSON.stringify({ name, _id }));
return { name, _id };
}
});
};
I'm getting undefined when i use getuser() in send()
exports.send = (req, res) => {
let {id}=req.body
let a=getuser(req.User._id)
let b=getuser(req.body.id)
console.log(a)
console.log(a)
let message = new messages({
user1: a,
user2: b,
});
message.save((err, saved) => {
if (err) {
return res.json(err);
} else {
return res.json(saved);
}
});
}
im getting undefined in
console.log(a)
console.log(a)
You probably want to use a Promise for the getuser method:
let getuser = (id) => new Promise((resolve, reject) => {
user.findById(id, (err, user) => {
if (err || !user) {
reject("wrong user id");
} else {
let { name, _id } = user;
console.log(JSON.stringify({ name, _id }));
resolve({ name, _id });
}
});
});
The operation looks asynchronous, so you need to wait for the result before continuing. This means that your getuser calls need to handle promise/async values:
let a = await getuser(req.User._id)
let b = await getuser(req.body.id)
Of course, await must be used in a function marked with async. Read up on Promises and async/await if any of this is unclear - they're absolutely imperative for working with databases, APIs etc.. It may be possible to use it immediately by changing your exports line:
exports.send = async (req, res) => {
But I don't know what environment this is for, so I can't say if that will work out of the box.
Please note that I haven't tested this at all, as it's a rather incomplete example to begin with. What I've suggested is merely theoretical.

How to return to parent function in JavaScript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have the following function at the moment, and I want to return "aaa" to the parent function (getStream), this is the code I have atm:
module.exports.getStream = (figure) => {
plotly.plot(figure, imgOpts, function(err, stream) {
if (err) {
console.log(err);
return "error";
}
return "aaa";
});
};
Right now, however, it returns undefined. What's the best solution to solve that problem?
The problem is that getStream does not return anything (therefore its return value is undefined). You have to add return before plotly or just remove curly braces. Also you'll have to return a promise, because that third argument of plotly.plot method is a callback function (I guess).
module.exports.getStream = (figure) =>
new Promise((resolve, reject) => {
plotly.plot(figure, imgOpts, function(err, stream) {
if (err) {
console.log(err);
reject("error");
}
resolve("aaa");
});
})
and then somewhere in the app:
const foo = async () => {
try {
const result = await getStream(figure)
console.log(result) // 'aaa'
} catch (err) {
console.log(err) // 'error'
}
}

Async Method Chaining? [duplicate]

This question already has answers here:
JS - chain async methods in sequence w/o callback or modification
(3 answers)
Closed 4 years ago.
I'm trying to create a class with async method chaining. However, I'm still setting the new values before I fully fetch the data from the database. Am I missing something?
I also don't want to use any third-party modules.
/* Class */
class UserDB {
constructor() {
this.user = {}
this.user.username = null
}
set(name, value) {
this.user[name] = value
return this
}
update() {
return new Promise((resolve, reject) => {
const db = MongoConnection.client.db('database').collection('users')
db.updateOne({ _id: this.user._id }, { $set: this.user}, (err, result) => {
if (err) reject(err)
resolve(this)
})
})
}
findByEmail(email) {
return new Promise((resolve, reject) => {
const db = MongoConnection.client.db('database').collection('users')
db.findOne({ email: email }, (err, result) => {
if (err) reject(err)
this.user = result
resolve(this)
})
})
}
}
module.exports = UserDB
/*execution*/
new UserDB().findByEmail('email#email.com')
.set('username', 'new_name')
.update()
Thats indeed interesting. You could overload the returned Promise with methods that attach the operation to a .then chain:
class AsyncChainable {
constructor() {
this._methods = {};
const that = this;
for(const key of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) {
this._methods[key] = function(...args) {
return that.chain(this.then(() => that[key](...args)));
}
}
chain(promise) { return Object.assign(promise, this._methods); }
}
Then use that in your custon class:
class User extends AsyncChainable {
login() {
return this.chain((async () => {
// some logic
})());
}
}
That way you can do:
(new User).login().login().then(console.log);

routing express node js

I have the following routes methods in my controller:
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
getUsuarioByEmail() {
this.app.get("/api/usuario/:usuarioEmail", (req, res) => {
let usuarioEmail = req.params.usuarioEmail;
this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
My question is related with the routes, for best practices we know that we should be using the name of the resources, in the first method I'm retrieving the list of Users and in the second I'm trying to retrieve the user by email. But when I try to call the api with: localhost:3000/api/usuario?usuarioEmail=xxxx#xxx.com it always call the first method and not the second. Is there something wrong with the way I'm defining my routes, or I have to change the complete path always.
In the url localhost:3000/api/usuario?usuarioEmail=xxxx#xxx.com, usuarioEmail is a query string; your rout is expecting it as a parameter. The correct usage given your routes would be:
localhost:3000/api/usuario/xxxx%40xxx.com
Where %40 represents the URI encoding of #.
If you actually wanted to use query strings, you would need to do something like this:
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
if (!req.query.usarioEmail) { // check for the query string
let usuarioEmail = req.params.usuarioEmail;
this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
} else {
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
}
});
}
Apparently you are mixing req.params with req.query
req.query
Works when you want to use an url just like the one you posted
localhost:3000/api/usuario?usuarioEmail=xxxx%40xxx.com
and the logic has to be setup in the /api/usuarios route
getListaUsuarios() {
this.app.get("/api/usuario", (req, res) => {
if (req.query.usuarioEmail) { //Aply your logic over here
/*If wont change the value of usuarioEmail, you should use
const instead of let*/
const usuarioEmail = req.params.usuarioEmail;
return this.usuario.getUsuarioByEmail(usuarioEmail).then((results) => {
if(!results) return res.status(404).json();
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
}
this.usuario.getListaUsuarios().then((results) => {
return res.status(200).json(results);
}).catch((error) => {
return res.status(500).send(error);
});
});
}
req.params
Is used when you want to do something like this
localhost:3000/api/usuario/micorreo%40email.com
And your route will look exactly like you have defined it
/api/usuario/:usuarioEmail
The value of :usuarioEmail is in req.params.usuarioEmail
If you want to know more about the req object, here's a link to the Express documentation

Categories