How to send an array with Express res.send() - javascript

I created this api to send back an array which I filled with data:
router.get('/getDevice/:instanceId', (req, res) => {
let deviceSum = [];
SingleAxis.findAll({where: {instanceid: req.params.instanceId}})
.then(singleAxis => {
if (singleAxis) {
for (let i = 0; i < singleAxis.length; i++) {
SingleAxisSegment.findAll({where: {singleAxisId: singleAxis[i].singleAxisId}})
.then(singleAxisSegments => {
let sum = 0;
for (let i = 0; i < singleAxisSegments.length; i++) {
sum += singleAxisSegments[i].counterAmount;
}
deviceSum.push({label: singleAxis[i].name, value: sum});
})
.catch(err => {return err});
}
console.log(deviceSum);
res.status(200).send(deviceSum);
} else {
res.status(200).json({message: 'Nothing found'});
}
})
.catch(err => res.status(400).json({message: 'Error', err}));
});
The console.log(deviceSum) prints out the following data:
[
{ label: 'Z5', value: 4404253 },
{ label: 'X9', value: 4423724 },
{ label: 'D6', value: 5506045 }
]
So the array contains data but when I test the api with a rest client I just get an empty array back.
How can I send the array back to the client?

You have to send the response inside the second findAll method. You are sending response before completing the second findAll promise.
Could you try this code.
I have used async await to make the code more readable.
router.get("/getDevice/:instanceId", async (req, res) => {
let deviceSum = [];
try {
let singleAxis = await SingleAxis.findAll({
where: { instanceid: req.params.instanceId }
});
if (singleAxis) {
for (let i = 0; i < singleAxis.length; i++) {
let singleAxisSegments = await SingleAxisSegment.findAll({
where: { singleAxisId: singleAxis[i].singleAxisId }
});
let sum = 0;
for (let i = 0; i < singleAxisSegments.length; i++) {
sum += singleAxisSegments[i].counterAmount;
}
deviceSum.push({ label: singleAxis[i].name, value: sum });
}
console.log(deviceSum);
res.status(200).send(deviceSum);
} else {
res.status(200).json({message: 'Nothing found'});
}
} catch (error) {
res.status(400).json({ message: "Error", err });
}
});

Related

Nodejs Execute after a recursive function is done

I have a controller that basically performs a recursive call to retrieve how categories and their deleted items, but a "category_item" has a property called "next_steps" which is an array of categories, so I need to retrieve those categories and their items as well.
So I made a recursive function, it works, but I need to run something else when it actually ends, how can I do that? here's my code:
const recoveryCategory = async (req, res) => {
try {
const categoryId = req.params.categoryId
const category = await nmCategorySvcV2.getByIdDeleted(categoryId)
if (category === null){
throw new Error("This category is not deleted.")
}
__recoveryRecursive(categoryId)
// run something after
res.json({ success: true, message: "Success." })
} catch (err){
res.json({ success: false, message: err.message })
}
}
const __recoveryRecursive = async (categoryId) => {
const category = await nmCategorySvcV2.getByIdDeleted(categoryId)
if (category === null){
return
}
await nmCategorySvcV2.update(categoryId, { deleted: false })
const categoryItens = await categoryItemSvcV2.getAllItensByCategory(categoryId)
for (let i = 0; i < categoryItens.length; i++) {
const categoryItem = categoryItens[i]
if (categoryItem.deleted == true) {
const item = await itemSvcV2.getByIdNoPopulate(categoryItem.item, categoryItem.page)
if (item.deleted == true) {
itemSvcV2.update(item._id, { deleted: false })
categoryItemSvcV2.updateItensProp(item._id, { deleted: false })
}
const itemPrice = await itemPriceSvcV2.getById(categoryItem.price)
if (itemPrice.deleted == true) {
itemPriceSvcV2.updateObject({ _id: itemPrice._id }, { deleted: false })
}
categoryItemSvcV2.update(categoryItem._id, { deleted: false })
if (categoryItem.next_steps.length > 0){
for (let j = 0; j < categoryItem.next_steps.length; j++){
const categryNextStep = categoryItem.next_steps[j].category
__recoveryRecursive(categryNextStep)
}
}
}
}
}
Just add await before the recursive call because it returns a promise wich must be handled .

I want to get attachments as well that comes with the message Gmail API

Okay so with this code I am able to get the actual mail content which comes by Email but what I want is I want to get message and attachment too. what can be done in order to list out attachments and later on giving option to download the attachments gmail api.
var ifrm = document.getElementById("iframe").contentWindow.document;
ifrm.body.innerHTML = getMessageBody(message.payload);
};
let getMessageBody = (message) => {
var encodedBody = "";
if (typeof message.parts === "undefined") {
encodedBody = message.body.data;
} else {
encodedBody = getHTMLPart(message.parts);
}
return Base64.decode(encodedBody);
};
let getHTMLPart = (arr) => {
for (var x = 0; x <= arr.length; x++) {
if (typeof arr[x].parts === "undefined") {
if (arr[x].mimeType === "text/html") {
return arr[x].body.data;
}
} else {
return getHTMLPart(arr[x].parts);
}
}
return "";
};
Gmail API when I click on message.
getOneMessage = (messageId) => {
return window.gapi.client.gmail.users.messages
.get({
userId: "me",
id: messageId,
})
.then(
(response) => {
this.setState({
message: response.result,
});
},
(err) => {
console.error("getMessage error", err);
}
);
};
handleMessageClick = (e) => {
const messageId = e.currentTarget.getAttribute("id");
this.getOneMessage(messageId);
Solution
You are using the Users.messages: get endpoint. This is fine to retrieve the message body, but to retrieve attachments you will have to use the Users.messages.attachments: get. Here you can find a link to the documentation.
Proposed code editing:
getAttachments = (message, callback) => {
var parts = message.payload.parts;
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part.filename && part.filename.length > 0) {
var attachId = part.body.attachmentId;
var request = gapi.client.gmail.users.messages.attachments.get({
'id': attachId,
'messageId': message.id,
'userId': userId
});
request.execute(function(attachment) {
callback(part.filename, part.mimeType, attachment);
});
}
}
}
getOneMessage = (messageId) => {
return window.gapi.client.gmail.users.messages
.get({
userId: "me",
id: messageId,
})
.then(
(response) => {
this.setState({
message: response.result,
});
// Get the attachment and do something with it
getAttachments(response.result, callback);
},
(err) => {
console.error("getMessage error", err);
}
);
};
handleMessageClick = (e) => {
const messageId = e.currentTarget.getAttribute("id");
this.getOneMessage(messageId);
Reference
Users.messages.attachments

returning null when using value out of block

I am trying to query one collection, get IDs from that and with that I am querying another collection and send the response. No issue in that. My issue is I am using foreach, so I am trying to get the value out of block and send the response. But it's throwing null. I consoled the value inside the block, its giving the response but I couldn't access the value out of the block.
Code
getDetails = async (req, res) => {
let data: any[] = [];
await employee.find({
_id: new mongoose.Types.ObjectId(req.body.id)
}, (err, obj) => {
if (err) {
console.log("No Such Employee")
} else {
obj.forEach(element => {
employer.find({
user: new mongoose.Types.ObjectId(element.user)
}, (err, details) => {
if (err) {
console.log("No such employer")
} else {
for (var i = 0; i < detail.length; i++) {
let p_info = {
"id": detail._id,
"fname": details[i].fname "lname": details[i].lname "phone": details[i].phone,
"email": details[i].email,
}
data.push(p_info); // I can get value here
}
}
})
});
res.send(data); // Cannot get value here
}
});
}
return response only when all your asynchronous db calls are done. see below:
getDetails = async(req, res) => {
let data = [];
let employees;
try {
employees = await employee.find({
_id: new mongoose.Types.ObjectId(req.body.id)
});
} catch (err) {
console.log("No Such Employee");
}
let emp_len = employees.length;
employees.forEach((emp_obj, idx) => {
let details = await employer.find({
user: new mongoose.Types.ObjectId(emp_obj.user)
});
for (var i = 0; i < patient.length; i++) {
let p_info = {
"id": patient._id,
"fname": details[i].fname,
"lname": details[i].lname,
"phone": details[i].phone,
"email": details[i].email,
}
data.push(p_info); // I can get value here
}
if (emp_len == idx + 1) {
res.send(data); // Cannot get value here
}
});
}

how to handle expressJs callback and how to update object's property inside a function?

I have two js files. i am able to get data from mongodb by calliing bookDao.getActiveBookByCategoryId().
My Problem
In categoryDao.js file i am trying to update resultJson.book_countinside BookDao.getActiveBookByCategoryId() method. but it is not updating. So may i know how to fix this.
here book_count property in resultJson is still 0.
categoryDao.js
module.exports.getAllActiveCategory = (callback) => {
Category.find({
is_delete : false
}, (error, result) => {
if(error) {
console.log(error);
callback(commonUtil.ERROR);
}
if(result) {
var categoryArray = [];
for(var i=0; i<result.length; i++) {
var categorySingle = result[i];
var resultJson = {
_id : categorySingle._id,
category_name : categorySingle.category_name,
created_on : categorySingle.created_on,
book_count : 0
}
BookDao.getActiveBookByCategoryId(categorySingle._id, (bookResult) => {
if(bookResult) {
if(bookResult.length > 0) {
resultJson.book_count = bookResult.length;
}
}
});
categoryArray.push(resultJson);
}
callback(categoryArray);
}
});
}
bookDao.js
module.exports.getActiveBookByCategoryId = (categoryId, callback) => {
Book.find({
is_delete : false,
category : categoryId
}, (error, result) => {
if(error) {
console.log(error);
callback(commonUtil.ERROR);
}
if(result) {
callback(result);
}
});
}
Try this, In your code categoryArray.push(resultJson); will not wait for BookDao.getActiveBookByCategoryId to finish because of async behavior.
module.exports.getActiveBookByCategoryId = (categoryId) => {
return Book.count({
is_delete: false,
category: categoryId
});
}
module.exports.getAllActiveCategory = async () => {
try {
// Find all category
const result = await Category.find({
is_delete: false
});
// Create array of promise
const promises = result.map(categorySingle => BookDao.getActiveBookByCategoryId(categorySingle._id));
// Get array of Category count
const data = await Promise.all(promises);
// update count in result
return result.map((categorySingle, i) => {
categorySingle.book_count = data[i];
return categorySingle;
});
} catch (error) {
console.log(error);
}
}

Want to send request in sync in node.js

I have a scenario that I want to fetch data from collection and insert into an array and then return that array.
router.route('/user/:_id/host/:_id/joineeList').get(function(req, res) {
var finalList = [];
Host.findOne({
_id : req.params._id,
}, function(err, host) {
if (err) {
res.send(err);
} else {
var count = host.joinees.length;
for (var i = 0; i < count; i++) {
console.log(host.joinees[i].userid);
var ID = host.joinees[i].userid;
var CODE = host.joinees[i].status_code;
User.findOne({
_id : host.joinees[i].userid
}, function(err1, user) {
if (err1) {
console.log(err1);
} else {
finalList.push({
"userId" : ID,
"name" : user.name,
"profilepic" : user.profilepic,
"status" : CODE
});
console.log(finalList);
// finalList[i].add = ("userId",ID);
// finalList[i].add = ("name",user.name);
// finalList[i].add = ("profilepic",user.profilepic);
// finalList[i].add = ("status",CODE);
}
});
}
}
});
});
Now, what is happening is that my array is returned null but data is inserted in finalList array also. Here is the console output:
[]
888888888888888888888888888888888888888888
[ { userId: '5485ae1159a751697e000003',
name: 'aaaa',
profilepic: 'https://graph.facebook.com/986962491123456/picture?type=large',
status: 0 } ]
------------------------------------------
[ { userId: '5485ae1159a751697e000003',
name: 'aaaa',
profilepic: 'https://graph.facebook.com/123456781319929/picture?type=large',
status: 0 },
{ userId: '5485ae1159a751697g7654003',
name: 'ssss',
profilepic: 'link',
status: 0 } ]
------------------------------------------
You could use this library - https://github.com/caolan/async#eachSeries. The method is eachSeries
Your code would look like this:
var async = require('async');
router.route('/user/:_id/host/:_id/joineeList').get(function (req, res) {
var finalList = [];
Host.findOne({
_id: req.params._id
}, function (err, host) {
if (err) {
res.send(err);
} else {
var count = host.joinees.length;
var limits = [];
for (var i = 0; i < count; i++) {
limits.push(i);
}
async.eachSeries(limits, function (i, callback) {
console.log(host.joinees[i].userid);
var ID = host.joinees[i].userid;
var CODE = host.joinees[i].status_code;
User.findOne({
_id: host.joinees[i].userid
}, function (err1, user) {
if (err1) {
console.log(err1);
} else {
finalList.push({
"userId": ID,
"name": user.name,
"profilepic": user.profilepic,
"status": CODE
});
callback();
}
});
}, function() {
console.log(finalList);
});
}
});
});
Let me know if it helped
You probably need the parallel method of the async library (or maybe map) check it out https://github.com/caolan/async#parallel
Thanks to #Vitaliy Zurian. I have used the following code, by using counter in the for loop
router.route('/user/:_id/host/:_id/joineeList').get(function (req, res) {
var finalList = [];
Host.findOne({
_id: req.params._id
}, function (err, host) {
if (err) {
res.send(err);
} else {
var count = host.joinees.length;
var limits = [];
for (var i = 0; i < count; i++) {
limits.push(i);
}
async.eachSeries(limits, function (i, callback) {
console.log(host.joinees[i].userid);
var ID = host.joinees[i].userid;
var CODE = host.joinees[i].status_code;
User.findOne({
_id: host.joinees[i].userid
}, function (err1, user) {
if (err1) {
console.log(err1);
} else {
finalList.push({
"userId": ID,
"name": user.name,
"profilepic": user.profilepic,
"status": CODE
});
callback();
}
});
}, function() {
console.log(finalList);
});
}
});
});

Categories