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 .
Related
var token = [];
for (let i = 1; i <= offlineMembers.length; i++) {
if (typeof(offlineMembers[i]) === 'string') {
ddb.get({
TableName: "DB",
Key: {
Username: offlineMembers[i]
}
}, (err, data) => {
if (err || Object.keys(data).length === 0) {
console.log(err);
} else {
token.push(data.Item.token)
}
})
}
}
console.log(token)
This is my code.
It always logs out the token array as empty [].
How can I wait for the execution of for loop to end and then run the console.log command?
You can use async/await to accomplish this (as mentioned in most comments).
Example:
let populateToken = (async () => {
const token = [];
// For Loop
return token;
})
const token = await populateToken();
console.log(token);
app.get("/api/users/:_id/logs", (req, res) => {
const id = req.params._id;
const { from, to, limit } = req.query;
** Here I tried to search for the matched user and it works successfully: **
User.findById({ _id: id }, (err, user) => {
if (!user || err) {
res.send("Unknown User Id !!");
} else {
**Then I tried to filter the log array with date **
// const username = user.username;
let responObject = {};
if (from) {
responObject["$gte"] = new Date(from).toDateString();
}
if (to) {
responObject["$lte"] = new Date(to).toDateString();
}
let filter = {
_id: id,
};
if (from || to) {
filter.date = responObject;
}
let nonNullLimit = limit ?? 500;
**try to build the array log and return it to the user but it always be empty and never return the exercises for the user **
Exercise.find(filter)
.limit(+nonNullLimit)
.exec((err, data) => {
if (err || !data) {
res.json([]);
} else {
const count = data.length;
const rowLog = data;
const { username, _id } = user;
const log = rowLog.map((item) => ({
description: item.description,
duration: item.duration,
date: new Date(item.date).toDateString(),
}));
console.log(log)
if (from && to) {
res.json({
username,
from: new Date(from).toDateString(),
to: new Date(to).toDateString(),
count,
_id,
log,
});
} else {
res.json({
username,
count,
_id,
log,
});
}
}
});
}
});
});
this is the result when I try to log all the exercises for the user
{"username":"ahmed","count":0,"_id":"62a9aab2743ddfc9df5165f2","log":[]}
function setUsersDefinitions(data, userID){
let users = new Array();
return new Promise((resolve)=>{
data.forEach(el => {
if (el.id_adder === userID) {
getUserName(el.id_added).then(u => {
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: el.id_added
})
}).catch(e=>{
console.log(e);
})
} else {
getUserName(el.id_adder).then(u=>{
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: el.id_adder
})
}).catch(e=>{
console.log(e);
})
}
})
resolve(users);
})
}
The problem is that when i try doing a console.log of the item generated it works but when it call Array.push method, it ignore that command.
What am I doing wrong?
Thanks in advance.
All of this should be done with async/await, and not by wrapping the whole lot in a Promise - it will hugely simplify your code:
async function setUsersDefinitions(data, userID){
let users = new Array();
for(var i=0;i<data.length;i++){
var el = data[i];
var id = (el.id_adder === userID) ? el.id_added : el.id_adder;
var u = await getUserName(id);
users.push({
username: u,
locked: el.locked !== null,
canUnlock: el.locked === userID,
id: id
});
}
return users;
}
(Note: Error handling omitted for brevity)
You should then await this function wherever you call it (must itself be within an async function):
async function doWork(){
var users = await setUsersDefinitions(some_data, some_userID);
console.log(users);
}
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 });
}
});
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);
}
}