This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
Is there a way to get the contents of variable data outside the function. I am so stuck, looked various forums in stackoverflow and but failed. I am trying to retrieve data from mongoose model and push those results into an array results and when i print results array, i get empty array .
var results = []
Model.find({firstName:name}, function(err,data){
if(err)
throw err;
data.forEach(function(element) {
console.log(element);
results.push(element);
});
});
console.log(results) --> []
But when i try to print the data inside the ForEach, I am was get the results, listed below.
0 => { _id: 5dc9953a2168993711903698,
id: 763,
firstName: 'Deepak',
lastName: 'Kalra',
image_id: 'No',
logged: false,
__v: 0
}
1 => {
_id: 5dc995546f0f88372080ea36,
id: 511,
firstName: 'Deepak',
lastName: 'Kalra',
image_id: 'No',
logged: false,
__v: 0
}
Entire code
alexa.intent("FirstName", {
"slots": { "name": "AMAZON.FIRST_NAME" },
"utterances": [
"sure {-|name}","{-|name}","my name is {-|name}"
]
},
function(request, response) {
var name = 'Deepak';
try {
var results = await Model.find({firstName:name});
console.log(results)
} catch (error) {
// Handle error.
}
// Model.find({firstName:name}, function(err,data){
// if(err)
// throw err;
// data.forEach(function(element) {
// console.log(element);
// results.push(element);
// });
// });
console.log(results);
});
Is there any solution to fix it. please help me
Because, console.log(results) executed before Model.find was finished.
Two things you can do here:
Put console.log(results) inside the callback.
Use async/await to get similar behaviour.
Example (callback):
Model.find({firstName:name}, function(err,data){
if(err)
throw err;
console.log(data); // data is already an array
});
Example (async/await):
try {
var results = await Model.find({ firstName: name });
console.log(results)
} catch (error) {
// Handle error.
}
Model.find already returns an array of document, so you don't have to run a loop to push them into an array.
UPDATED
alexa.intent("FirstName", {
"slots": { "name": "AMAZON.FIRST_NAME" },
"utterances": [
"sure {-|name}", "{-|name}", "my name is {-|name}"
]
},
async function (request, response) {
var name = 'Deepak';
try {
var results = await Model.find({ firstName: name });
console.log(results)
} catch (error) {
// Handle error.
}
});
Notice the async in front of function.
Related
I am creating a website and I want to seed some data.
I want to create two articles with two comments each :
var mongoose = require("mongoose"),
Article = require("./models/articles.js"),
Comment = require("./models/comments.js");
var articleData = [
{
title: "Fast Cars",
author: "Steve Novak",
company: "AthLead",
body: "SOME TEXT"
},
{
title: "New Design",
author: "Kevin Garnett",
company: "Revoos",
body: "COOL ARTICLE"
}
];
var commentData = [
{
body: "I really love the new design",
author: "Mark Cuban"
},
{
body: "This is hitting my funny bone",
author: "Lisa Jones"
}
];
I am Deleting all past comments and articles.
Then for each article I am first creating the article and then pushing two comments.
I am getting a problem at saving the newly formed article to the database :
Placing article.save() at 1. causes parallel save() error to occur
Whereas placing at 2. causes no comment to be saved.
function seedDB() {
Comment.deleteMany({}, function (err) {
if (err) {
console.log(err);
}
Article.deleteMany({}, function (err) {
if (err) {
console.log(err);
}
articleData.forEach(function (article) {
Article.create(article, function (err, article) {
if (err) {
console.log(err);
} else {
commentData.forEach(function(comment) {
Comment.create(comment, function (err, comment) {
if (err)
console.log(err);
else {
article.comments.push(comment);
// PROBLEM
// 1. article.save();
}
})
})
// PROBLEM
//2. article.save();
}
});
});
});
});
});
console.log("Database Reset");
}
module.exports = seedDB;
You are currently in callback hell and using async/await willl go a long way making your code readable and thus makes it easy to debug.
Consider the following workflow that uses async/await
async function seedDB() {
try {
// clean up all comments
await Comment.deleteMany({}).exec()
// clean up all articles
await Article.deleteMany({}).exec()
// create articles
await Article.create(articleData)
// create comments
const comments = await Comment.create(commentData)
// update articles with the new comments
const updatedArticles = await Article.updateMany(
{},
{ '$set': { comments } }
).exec()
console.log(updatedArticles)
} catch (err) {
console.error(err)
}
}
You can pass an array of documents to Model.create, just create comments first then use Array.map to create a new array from articletData with comments assigned to each article
using async/await:
async function seedDB() {
...
const comments = await Comment.create(commentData);
const articles = await Article.create(articleData.map(article => { article.comments = comments; return article }));
...
using Promise.then():
function seedDB() {
...
Comment.create(commentData).then(comments =>
Article.create(articleData.map(article => { article.comments = comments; return article })).then(articles => {
});
});
...
When you first Article.create..., on successfull creation the function returns the article object or a error on the other side.
You need to run the forEach loop in the newly created article for achieve each article contain the Comments.
you need to work with the existed newly created article data.
Example
articleData.forEach(function (article) {
Article.create(article, function (err, article) {
if (err) {
console.log(err);
} else {
article.update(
{ "_id": ObjectId(article.id) },
{ $push: { comments: commentData } }
);
// OR try something like
// article.comments = commentData
// OR
// article.comments.insert(commentData)
article.save();
}
});
});
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have been trying to create a JSON object with the data that I pull from MongoDB database.
Last line res.status(200).json(userData) seems to return a response before
the data processing is over, so I get an empty object without processed data as a response. Any ideas on how to solve this problem?
// chats are defined before, but excluded here to make a code easier to read
let userData = {};
chats.forEach(function(chat){
let chatId = chat.id;
let userIds = chat['userIds'];
UserAccountingData.find({userId: {$in : userIds}}, function(err, userAccountingData){
if(err){
console.log(err);
res.status(404).json('User data not found.');
return;
} else {
userAccountingData.forEach(function(data){
console.log({
imageUrl: data.imageUrl,
firstName: data.firstName,
lastName: data.lastName
});
userData[data.userId] = {
imageUrl: data.imageUrl,
firstName: data.firstName,
lastName: data.lastName
};
});
}
});
});
res.status(200).json(userData);
Console.log shows that there is a data coming from the database:
{ imageUrl: 'www.test.de', firstName: 'Fender', lastName: 'Fen' }
{ imageUrl: 'www.test.de', firstName: 'Baveler', lastName: 'Bav' }
Thank you for your time
This is because the UserAccountingData.find runs asynchronously. So we need to add async/await logic to this code.
First, define the find function.
const findUserAccountingData = (userIds) => new Promise((resolve, reject) => {
UserAccountingData.find({ userId: { $in: userIds } }, function (err, userAccountingData) {
if (err) {
return reject(err);
}
resolve(userAccountingData)
})
});
Next, modify the original code like below.
let userData = {};
try {
for (let chat of chats) {
let chatId = chat.id;
let userIds = chat['userIds'];
const userAccountingData = await findUserAccountingData(userIds)
userAccountingData.forEach(function (data) {
console.log({
imageUrl: data.imageUrl,
firstName: data.firstName,
lastName: data.lastName
});
userData[data.userId] = {
imageUrl: data.imageUrl,
firstName: data.firstName,
lastName: data.lastName
};
});
}
} catch (error) {
console.log(error);
// res.status(404).json('User data not found.'); // error doesn't occur when user data not exists.
res.status(500).json(JSON.stringify(error));
}
res.status(200).json(userData);
Finally you need to mark the calling function as async.
so I have an array from another function that passes res which is a list looking like this:
[ RowDataPacket { UserID: 26 }, RowDataPacker { UserID: 4 } ]
it stores user id's, what I want is a function that finds the user id's username, and stores them in another array. This is what I have:
function getThem(res, params) {
var promises = res.map(function (item) { // return array of promises
// return the promise:
for (i = 0; i < Object.keys(res).length; i++) {
console.log("user: ", res[i].UserId);
getUsernameFromId(res[users.length].UserId).then(function() {
console.log("username: ", res[0].username);
users.push(res[0].username);
});
}
}, function (err) {
console.error(err);
});
Promise.all(promises).then(function () {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}
output in console:
user: 26
user: 4
user: 26
user: 4
users: []
username: undefined
username: undefined
username: undefined
username: undefined
so how can I wait for the for loop to complete the mysql call? Maybe there is another way of doing this?
edit: don't mind the undefined usernames, it's easy to fix later. Just tell me how I can have those undefined inside an array
Assuming (have to assume, because your code seems to use res like a majick object that has everything you need before you do anything with it) the actual res looks like
[ { UserID: 26 }, { UserID: 4 } ]
and getUsernameFromId returns an object with a username property, like
{ username: 'blah', ...otherproperties }
getThem can be simply
function getThem(res, params) {
return Promise.all(res.map(({UserID}) => getUsernameFromId(UserId).then(({username}) => username)))
.then(users => {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}
or in "old school" javascript
function getThem(res, params) {
return Promise.all(res.map(function (_ref) {
var UserID = _ref.UserID;
return getUsernameFromId(UserId).then(function (_ref2) {
var username = _ref2.username;
return username;
});
})).then(function (users) {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}
I have a big issue with my function in sails.js (v12). I'm trying to get all userDetail using async (v2.3) for deep populating my user info:
UserController.js:
userDetail: function (req, res) {
var currentUserID = authToken.getUserIDFromToken(req);
async.auto({
//Find the User
user: function (cb) {
User
.findOne({ id: req.params.id })
.populate('userFollowing')
.populate('userFollower')
.populate('trips', { sort: 'createdAt DESC' })
.exec(function (err, foundedUser) {
if (err) {
return res.negotiate(err);
}
if (!foundedUser) {
return res.badRequest();
}
// console.log('foundedUser :', foundedUser);
cb(null, foundedUser);
});
},
//Find me
me: function (cb) {
User
.findOne({ id: currentUserID })
.populate('myLikedTrips')
.populate('userFollowing')
.exec(function (err, user) {
var likedTripIDs = _.pluck(user.myLikedTrips, 'id');
var followingUserIDs = _.pluck(user.userFollowing, 'id');
cb(null, { likedTripIDs, followingUserIDs });
});
},
populatedTrip: ['user', function (results, cb) {
Trip.find({ id: _.pluck(results.user.trips, 'id') })
.populate('comments')
.populate('likes')
.exec(function (err, tripsResults) {
if (err) {
return res.negotiate(err);
}
if (!tripsResults) {
return res.badRequest();
}
cb(null, _.indexBy(tripsResults, 'id'));
});
}],
isLiked: ['populatedTrip', 'me', 'user', function (results, cb) {
var me = results.me;
async.map(results.user.trips, function (trip, callback) {
trip = results.populatedTrip[trip.id];
if (_.contains(me.likedTripIDs, trip.id)) {
trip.hasLiked = true;
} else {
trip.hasLiked = false;
}
callback(null, trip);
}, function (err, isLikedTrip) {
if (err) {
return res.negotiate(err);
}
cb(null, isLikedTrip);
});
}]
},
function finish(err, data) {
if (err) {
console.log('err = ', err);
return res.serverError(err);
}
var userFinal = data.user;
//userFinal.trips = data.isLiked;
userFinal.trips = "test";
return res.json(userFinal);
}
);
},
I tried almost everthing to get this fix but nothing is working...
I am able to get my array of trips(data.isLiked) but I couldn't get my userFInal trips.
I try to set string value on the userFinal.trips:
JSON response
{
"trips": [], // <-- my pb is here !!
"userFollower": [
{
"user": "5777fce1eeef472a1d69bafb",
"follower": "57e44a8997974abc646b29ca",
"id": "57efa5cf605b94666aca0f11"
}
],
"userFollowing": [
{
"user": "57e44a8997974abc646b29ca",
"follower": "5777fce1eeef472a1d69bafb",
"id": "5882099b9c0c9543706d74f6"
}
],
"email": "test2#test.com",
"userName": "dany",
"isPrivate": false,
"bio": "Hello",
"id": "5777fce1eeef472a1d69bafb"
}
Question
How should I do to get my array of trips (isLiked) paste to my user trips array?
Why my results is not what I'm expecting to have?
Thank you for your answers.
Use .toJSON() before overwriting any association in model.
Otherwise default toJSON implementation overrides any changes made to model associated data.
var userFinal = data.user.toJSON(); // Use of toJSON
userFinal.trips = data.isLiked;
return res.json(userFinal);
On another note, use JS .map or _.map in place of async.map as there is not asynchronous operation in inside function. Otherwise you may face RangeError: Maximum call stack size exceeded issue.
Also, it might be better to return any response from final callback only. (Remove res.negotiate, res.badRequest from async.auto's first argument). It allows to make response method terminal
I am using a function to find clients from my mongodb database using node js.
In my query I'm trying to get the function to output the data without the "_id"
but it's not working.
function findClient(Fname,res){
let query = {name:Fname}
dbo.collection("clients")
.find(query,{ _id: 0,name: 1 ,last: 1, age:1})
.toArray(function(err, result) {
if (err) throw err;
result = JSON.stringify(result)
res.render(`./pages/findRes`,{data:result})
console.log(result)
});
}
You don't need to use toArray here.
function findClient(Fname, res) {
let query = { name: Fname }
dbo.collection("clients").find(query, { _id: 0, name: 1, last: 1, age: 1 }, function (err, result) {
if (err) throw err;
result = JSON.stringify(result)
res.render(`./pages/findRes`, { data: result })
console.log(result)
});
}
Basic example here: https://mongoplayground.net/p/WzCaITFhCHM
This should work.