Sequelize return response with nested loops - node.js

I am looping through and inserting elements in my addAll method. Once this has finished, I would like to return a response. My code currently works, but I am not sure how to get the response to happen.
Route
.post(function (req, res) {
var screening_module = Screening_module.build();
screening_module.screening_module = req.body.module;
screening_module.screening_module.organization_id = req.user.organization_id;
screening_module.addAll(function (success) {
res.json({message: 'screening_module created!'});
},
function (err) {
res.status(err).send(err);
}); });
AddAll
addAll: function (onSuccess, onError) {
var screening_module = this.screening_module;
screening_module.selectedUser.forEach(function (user) {
Screening_module.create({
organization_id: screening_module.organization_id,
supervisor: screening_module.supervisor.id,
name: screening_module.name,
description: screening_module.description,
deadline: screening_module.deadline,
category_id: screening_module.category.id,
screening_module_type_id: screening_module.type.id,
user_id: user.id
}).then(function (createdScreeningModule) {
Screening.create({
user_id: createdScreeningModule.dataValues.user_id,
screening_module_id: createdScreeningModule[null]
}).then(function (createdScreening) {
screening_module.selectedSkillsets.forEach(function (skillset) {
Screening_has_skillset.create({
screening_id: createdScreening[null],
skillset_id: skillset.id
})
})
})
})
});
},

Promise is your friend here
var Promise = require("bluebird");
addAll: function (onSuccess, onError) {
var screening_module = this.screening_module;
Promise.each(screening_module.selectedUser, function (user) {
return Screening_module.create({
organization_id: screening_module.organization_id,
supervisor: screening_module.supervisor.id,
name: screening_module.name,
description: screening_module.description,
deadline: screening_module.deadline,
category_id: screening_module.category.id,
screening_module_type_id: screening_module.type.id,
user_id: user.id
}).then(function (createdScreeningModule) {
return Screening.create({
user_id: createdScreeningModule.dataValues.user_id,
screening_module_id: createdScreeningModule[null]
}).then(function (createdScreening) {
return Promise.each(screening_module.selectedSkillsets, function (skillset) {
return Screening_has_skillset.create({
screening_id: createdScreening[null],
skillset_id: skillset.id
});
});
});
});
}).then(onSuccess, onError);
},
Untested, but hopefully give you an idea of how to handle. IMO, this kind of deep nesting is a code smell, and you might need to consider the design again

Related

How to handle async when making mongoose query in each array element in express?

On the following post method, I'm having some issues due to moongose async. res.send(suggestions) is executed first then Expense.findOne.exec
app.post('/suggestions', async function(req, res) {
const suggestions = await req.body.map((description) => {
Expense.findOne({ description: new RegExp(description, 'i') }).exec((err, result) => {
if (result) {
console.log(result.newDescription);
return {
description,
newDescription: result.newDescription,
category: result.category,
subcategory: result.subcategory
};
}
});
});
res.send(suggestions);
});
The result is a array of null values. How can I executed a query for each item, then execute res.send(suggestion)?
Found solution with the following code:
app.post('/suggestions', async function(req, res) {
try {
if (req.body.length > 0) {
const suggestions = req.body.map((description) =>
Expense.findOne({ description: new RegExp(description, 'i') })
);
const results = await Promise.all(suggestions);
return res.send(results);
}
} catch (e) {
console.log('error', e);
}
});

GraphQL Sent Proper Data but Variable is Undefined

Hopefully I'm not overlooking something stupid here, but here's the problem.
I'm fetching this Smartsheet data using promise:
var getWorkspaces = async function(args) {
var smartsheet = client.createClient({ accessToken: "key" });
await smartsheet.workspaces.listWorkspaces()
.then(async function(workspaceList) {
var data = await workspaceList.data;
console.log("returning");
console.log(data);
return data;
})
.catch(function(error) {
console.log(error);
});
}
and this is my resolvers:
var resolvers = {
Query: {
workspaces: async () => {
var workspaceData = await getWorkspaces();
console.log("sending");
console.log(workspaceData);
return workspaceData;
}
}
};
Why is this the console output:
returning
[
{
id: 000,
name: 'nname',
accessLevel: 'ADMIN',
permalink: 'link'
},
{
id: 000,
name: 'name',
accessLevel: 'ADMIN',
permalink: 'link'
},
{
id: 000,
name: 'name',
accessLevel: 'ADMIN',
permalink: 'link'
}
]
sending
undefined
And more specifically, why is workspaceList undefined? I've been at this for hours and cannot find a solution.
The issue here is that your return workspaceData is within a callback function of .then(), so you're returning in the callback, not in the getWorkspaces() function. When you say .next(), the request happens asynchronously. When you use await, the current thread waits for the response and executes it without needing a callback–– a synchronous call. await implicitly calls .next(), and adding try/catch is equivalent to .catch().
var getWorkspaces = async function(args) {
try {
var smartsheet = client.createClient({ accessToken: "key" });
var workspaceList = await smartsheet.workspaces.listWorkspaces();
var data = workspaceList.data;
console.log("returning");
return data;
} catch (err) {
console.log(err);
}
}

wait for result from an async method

I'm trying to call an async method from for loop, but it doesn't wait for the result from that method.
Below is my code:
async function fetchActivityHandler (req, reply) {
esClient.search({
index: 'user_activity',
type: 'document',
body: {
_source : ["userId","appId","activity","createdAt","updatedAt"],
query: {
bool : {
must:[
{match : { 'userId': req.params.id }}
]
}
}
}
},async function (error, response, status) {
if (error){
console.log('search error: '+error)
}
else {
var activities = [];
//await Promise.all(response.hits.hits.map(async function(hit){
for (const hit of response.hits.hits) {
var activity = hit._source
var app = await fetchAppDetails(activity.appId);
console.log(app);
activity = {...activity,app : app}
activities.push(activity);
console.log(activity);
}
reply.status(200).send(activities);
}
});
}
async function fetchAppDetails (appId) {
esClient.get({
index: 'app',
type: 'document',
id: appId
}, function (err, response) {
console.log(response._source);
return (response._source);
});
}
What may be the problem. I'm using async and await, but it is not working.
Await works with promise. You should wrap your function with promise to get this work. Hope this will help you. Also you do not need to use async on fetchActivityHandler function. Only in the callback which you have already used.
function fetchAppDetails (appId) {
return new Promise((resolve,reject)=>{
esClient.get({
index: 'app',
type: 'document',
id: appId
}, function (err, response) {
if(err){
reject(err);
}
else{
resolve(response)
}
});
});
}

Bluebird promises - each function

Thank in advance for the help.
While using Bluebird promises, I have a series of promises running. During the last promise, I want to run one function multiple times for each object in an array.
Below there is the pseudocode:
var userArray = [
{
name: "John",
email: "John#email.com"
},
{
name: "Jane",
email: "jane#email.com"
}];
var functionOne = function() {
//returns Promsie object
};
var functionTwo = function() {
//returns promise object
};
var createUser = function(user) {
return User.findOrCreate({email: user.email},{
name: user.name,
email: user.email
});
};
functionOne()
.then(functionTwo)
.each(createUser(userArray))
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
I know I'm not using the each function correctly. What's the correct way to implement this using Bluebird?
As I understand you want to take some asynchronous actions for elements from array. Then please check the following example:
var Promise = require('bluebird');
function createUsersFromArray(userArray){
return Promise.each(userArray, function(signleUser){
return createUserFunction(signleUser);
});
}
or
return Promise.each(userArray, createUserFunction);
functionOne()
.then(functionTwo)
.then(function(){
return createUsersFromArray(userArray);
})
//or just .then(createUsersFromArray) if functionTwo return this array
.then(function(createdUsers){
//here you may retrieve users and make some magic with them
console.log(createdUsers);
})
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
I also recommend using "all" instead of "each"
Check the examples below:
return Promise.all(userArray.map(function(singleUser){
return doSomethingWithUser(singleUser);
}));
or
return Promise.all(userArray.map(doSomethingWithUser));
'all' will notify you if all the actions are taken correctly.
How to use promises (best practice):
http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
https://blog.domenic.me/youre-missing-the-point-of-promises/
The most straightforward implementation:
functionOne()
.then(functionTwo)
.then(function(){
return bluebird.each(userArray, createUser);
})
.then(function onComplete() {
console.log("Complete");
})
.catch(function onError() {
console.log("Um...it's not working");
});
You should use .map instead of .each if you want to access the results of all of those creates.
Thanks #Roman #Yuri for the help! My now working code is below:
var userArray = [
{
name: "John",
email: "John#email.com"
},
{
name: "Jane",
email: "jane#email.com"
}];
var functionOne = function() {
//returns Promise object
};
var functionTwo = function() {
//returns Promise object
};
var createUser = function(singleUser) {
//returns Promise object containing creating User
};
functionOne()
.then(functionTwo)
.then(function() {
return Promise.map(userArray, createUser);
})
.then(function onComplete(response) {
console.log("Complete:" + JSON.stringify(response));
})
.catch(function onError() {
console.log("Um...it's not working");
});

Added property don't get encoded with JSON

I am trying to get all course from the database and then add course_has_users if it exist.
The code works until I try to JSON encode it. Then I lose course_has_users when my angular front-end receives it.
Course.findAll({include: [
{model:Course_has_material},
{model:Course_has_competence},
{model:Organization},
{model:Module_type},
{model:Category},
{model:User, as:'mentor'}
],
where: {organization_id: user.organization_id}
}).then(function (courses) {
async.each(courses, function (course, callback) {
Course_has_user.findAll({
where: {user_id: user.user_id, course_id:course.id}
}, {}).then(function (course_has_user) {
course.course_has_users = course_has_user;
callback();
})
}, function (err) {
onSuccess(courses);
});
});
Route
.get(function (req, res) {
var course = Course.build();
course.retrieveAll(req.user, function (courses) {
if (courses) {
res.json(courses);
} else {
res.status(401).send("Courses not found");
}
}, function (error) {
res.send("Courses not found");
});
})
async.each will just iterate through it.
Use async.map and return course after setting course has users on it.
It should just work then. ;)
Course.findAll({include: [
{model:Course_has_material},
{model:Course_has_competence},
{model:Organization},
{model:Module_type},
{model:Category},
{model:User, as:'mentor'}
],
where: {organization_id: user.organization_id}
}).then(function (courses) {
async.map(courses, function (course, callback) {
Course_has_user.findAll({
where: {user_id: user.user_id, course_id:course.id}
}, {}).then(function (course_has_user) {
course.course_has_users = course_has_user;
callback(null, course);
})
}, function (err, _courses) {
// Note that we use the results passed back by async here!
onSuccess(_courses);
});
});
So you could also do, to simplify things a bit
Course.findAll({include: [
{model:Course_has_material},
{model:Course_has_competence},
{model:Organization},
{model:Module_type},
{model:Category},
{model:User, as:'mentor'}
],
where: {organization_id: user.organization_id}
})
.map(function (course) {
return Course_has_user.findAll({
where: {user_id: user.user_id, course_id:course.id}
}, {})
.then(function (course_has_user) {
course.course_has_users = course_has_user;
return course;
})
})
.then(onSuccess);
});
The problem was with Sequelize and fixed the issue by changing it's toJSON method and using async.map
Haven't tested with async.each but should work without map
instanceMethods: {
toJSON: function () {
var json = this.values;
json.course_has_users = this.course_has_users;
return json;
},
};
Retrieve method
retrieveMyCourses: function (user, onSuccess, onError) {
Course.findAll({include: [
{model:Course_has_material},
{model:Course_has_competence},
{model:Organization},
{model:Module_type},
{model:Category},
{model:User, as:'mentor'}
],
where: {organization_id: user.organization_id}
}).
then(function (courses) {
async.map(courses, function (course, callback) {
Course_has_user.findAll({
where: {user_id: user.user_id, course_id:course.id}
}, {}).then(function (course_has_user) {
course.course_has_users = course_has_user;
callback(null, course);
})
}, function (err, _courses) {
var test = JSON.parse(JSON.stringify(_courses));
onSuccess(_courses);
});
});
},
Route
router.route('/api/myCourses')
// Get all courses
.get(function (req, res) {
var course = Course.build();
course.retrieveMyCourses(req.user, function (courses) {
if (courses) {
res.json(courses);
} else {
res.status(401).send("Courses not found");
}
}, function (error) {
res.send("Courses not found");
});
});
Sequelize issue:
https://github.com/sequelize/sequelize/issues/549

Resources