I have an array that I'd like to fill with objects, but the console prints out []. I know this is a problem with the async nature of mongoose, but I'm not sure how to fix it... I want itemCart to be filled with all the user's items.
Any guidance/help would be appreciated. Thanks!
Here is the code:
let itemCart = [];
User
.findById(req.params.username)
.then(user => {
for (let i = 0; i < user.cart.length; i++) {
let itemId = user.cart[i];
Item.findById(itemId).then(item => {
itemCart.push(item);
});
}
console.log(itemCart); // returns []
})
.catch(err => {
console.error(err)
});
You can apply async/await like this:-
let itemCart = [];
User
.findById(req.params.username)
.then(async user => {
for (let i = 0; i < user.cart.length; i++) {
let itemId = user.cart[i];
Let item = await Item.findById(itemId);
itemCart.push(item);
}
console.log(itemCart); // now it will return the array
})
.catch(err => {
console.error(err)
});
Related
I have the following javaScript code for Nodejs to update data in MongoDB.
I have a list of products that I want update (called itemsToBeUpdated). (Update the preference value in the order that they are passed-in)
Once all the updates have been completed, I would like to go and retrieve the product list by calling the function getProducts(req, res);
where should I put the getProducts(req, res)? Not position A because Product.findByIdAndUpdate is async so it will get to position A before the findByIdAndUpdate is completed.
Not position B because there are more items to loop through.
const updateAndRefreshProducts = (req,res) => {
const itemsToBeUpdated = req.body;
const counter = someValue
for(let i = 0; i<itemsToBeUpdated.length; i++){
const newPreference = counter;
counter++;
condition= {_id: itemsToBeUpdated[i]._id};
Product.findByIdAndUpdate(condition, {preference:newPreference})
.then(result => {
console.log('performing update completed for result' + result.name +" : ", result.preference);
//position B
})
.catch(error =>{
console.log('error', error);
});
}
//position A
}
thanks
There are a couple of way to handle this, the easiest way to accomplish this will be to utilize Promise.all().
You may want to read on this documentation
const updateAndRefreshProducts = (req,res) => {
const itemsToBeUpdated = req.body;
const productUpdatePromises = []
const counter = someValue
for(let i = 0; i<itemsToBeUpdated.length; i++){
const newPreference = counter;
counter++;
condition= {_id: itemsToBeUpdated[i]._id};
const productUpdatePromise = Product.findByIdAndUpdate(condition{preference:newPreference})
productUpdatePromises.push(productUpdatePromise)
}
await Promise.all(productUpdatePromises).then((results) => {
console.log(results);
//Called your get all products here
})
.catch((error) => {
console.error(error.message);
});
}
I could not get the a nested logic to work. I need to combined data from 2 table and return it to the request. I do not want a join table as I need to return an individual record from tableA first then combine with tableB record before it is returned. Below is my simplified code
exports.get_caution_reasons = async (req, res) => {
let return_data = [];
await db.sequelize.query("SELECT TableA xxxxx",{
type: QueryTypes.SELECT
}).then(recordA => {
for (let index = 0; index < recordA.length; index++) {
return_data.push({recordA[index].xxx, recordA[index].yyy})
db.sequelize.query("SELECT TableB xxxxx WHERE zzz=recordA.zzz",{
type: QueryTypes.SELECT
}).then(recordB => {
for (let index = 0; index < recordB.length; index++) {
return_data.push({recordB[index].xxx, recordB[index].yyy})
}
})
}
res.status(200).json({data: return_data});
})
};
It only return the record for TableA only. I tried various async and await to get the recordB in there but without success. Any help is useful.
Probably something like that should work:
exports.get_caution_reasons = async (req, res, next) => {
try {
let options = { type: QueryTypes.SELECT }
let data = []
let result_a = await db.sequelize.query("SELECT TableA xxxxx", options)
for (let index = 0; index < result_a.length; index++) {
data.push({ /* whatever you need... */ })
let result_b = await db.sequelize.query("SELECT TableB xxxxx WHERE zzz=recordA.zzz", options)
for (let index = 0; index < result_b.length; index++) {
data.push({ /* ... */ })
}
}
res.json({ data })
} catch (err) {
next(err)
}
}
I have code written
function getDetails (req, res) {
const dbQuery = `call spGetSLAReportsDetails('${req.body.domainId}', ${req.body.days},'${req.body.type}','${req.body.app}')`
try {
connectDatabase(dbQuery).then((rows) => {
if (!_.isEmpty(rows.dbData) && !_.isEmpty(rows.dbData[0])) {
const resultList = []
rows.dbData.pop()
var bar = new Promise((resolve, reject) => {
rows.dbData[0].forEach((element, index, array) => {
let query = `select * from YCW.YWFWIC ic where ic.witem=${element.witem} and ic.reqno=${element.reqno};`
connectDatabase(query).then((data) =>{
for (var i = 0; i < data.dbData.length; i++) {
element[data.dbData[i]["cfield"]] = data.dbData[i]["cvalue"]
}
resultList.push(element)
// console.log(resultList)
}).catch((err) => {
console.log(err)
})
if (index === array.length -1) resolve();
});
});
bar.then(() => {
console.log(resultList);
});
res.status(msgCodeJson.ERR004.code).send({
result: resultList })
} else {
console.log("empty array")
res.status(msgCodeJson.ERR004.code).send({
message : "No data found"
})
// httpResponseHandlerError(res, msgCodeJson.ERR001.code, msgCodeJson.ERR001.msg)
}
}).catch(() => {
httpResponseHandlerError(res, msgCodeJson.ERR002.code, msgCodeJson.ERR002.msg)
})
} catch (err) {
httpResponseHandlerError(res, msgCodeJson.ERR009.code, msgCodeJson.ERR009.msg)
}
}
module.exports.getDetails = getDetails
i want data to be fit in resultlist but i get empty list after all operation.
while in foreach loop i am getting proper output.
kindly help in issue.
i tried with async foreach loop but some syntax error is coming.
kindly help
as mentioned in the comment of the code you're using
Best way to wait for .forEach() to complete
This is OK if there is no async processing inside the loop.
yet you have an async function inside your forEach callback, namly this:
connectDatabase(query).then((data) => {
for (var i = 0; i < data.dbData.length; i++) {
element[data.dbData[i]["cfield"]] = data.dbData[i]["cvalue"]
}
resultList.push(element)
}).catch((err) => {
console.log(err)
})
you'll need to resolve the "outer/parent" promise from inside the "inner/child" promise
I suggest using a regular good old for loop and/or checking the count of resolved promises against the rows.dbData[0].length and calling a final code/function once they match
I want to save an object multiple times, with a change to the date field - adding one month per iteration.
A for loop doesn't work due to node async nature.
const saveMany = (req, res, obj, data) => {
let saves = [];
if (data.frequency === 'monthly') {
let i = 0;
for (let i = 0; i < data.reccuring_length; i++) {
const newEntry = new obj(data);
if (i != 0) newEntry.created_date.addMonths(1) //using datejs
newEntry.save((err, entry) => {
if (err) {
return res.status(400).send({
message: err
});
}
saves.push(entry);
})
}) //end of for loop
return res.json(saves)
} //end of if
}
I've seen stuff about promises / the async library but can't make a working implementation (I am new to this though so could be missing something obvious).
Any help is appreciated :)
EDIT:
Saving To MongoDB In A Loop
Found this link which is relevant, but if anyone has other suggestions that would be great.
EDIT 2:
Just realised my code has camelcase and snake case, changing in my code to make all object data snake case.
I think you can do somethings like that:
const saveMany = async (req, res, obj, data) => {
let saves = [];
if (data.frequency === 'monthly') {
let i = 0;
for (let i = 0; i < data.reccuring_length; i++) {
const newEntry = new obj(data);
if (i != 0) newEntry.created_date.addMonths(1) //using datejs
try{
const entry= await newEntry.save();
saves.push(entry);
} catch(err) {
return res.status(400).send({ message: err });
}
}) //end of for loop
return res.json(saves)
} //end of if
}
how to make this function work. Only a promise comes back to me.
codeProducts.forEach((code, index) => {
const qt = app.db('products').where('code',code).first().then(result => result.quantity)
data[index] = {
code: code,
quantity: qt
}
})
return data
There is two or three ways that you can solve this-
Approach: 1
I will make just one call to database.(I love my database :D) as-
let codeProducts = [55, 68, 96];
knex('products')
.whereIn('code', codeProducts)
.then((results) => {
// response to api call
console.log(results);
});
Approach: 2 (I don't like this approach. Too many call on db)
async function getData(codes) {
try {
let results = [];
for (let i = 0; i < codes.length; i++) {
let dbQuery = await knex('products').where('code', codes[i]).first();
results.push(dbQuery);
}
return results;
} catch (e) {
console.log(e);
}
}
const codeProducts = [54, 95];
getData()
.then((res) => {
console.log(res);
})
let data = codeProducts.map((code, index) => {
return app.db('products').where('code',code).first()
.then(result => {
return {
code: code,
quantity: result.quantity
}
})
})
return data
This code should fix your problem. You are accessing the quantity outside of the promise. In order to set the quantity on the data array, you need to do it inside the then