Im building a Deck building application for a card game, i also have a database setup that i use to sell these cards i play with, this deck builder effectively allows me to take from the stock of the sellable stock (i.e. if i have 1 of x card, and i add that to a deck, it sets the countInStock
of that item in the database to 1 less of what it was.) however when i delete the entire {deck}
i need to re-seed into the sellable stock everything that was in [deck.cards]
which is an array of {Card}
objects, Im trying to simply loop over each object in that array, find that card, find the product in the database, set the product to 1 (as each card, can be the same card, but it will be a different object) therefore i simply just need to increase the countInStock
by 1, when i hit this endpoint, it will place back in to stock 1 object, but it will seemingly ignore the other objects in the forEach loop and not add more to the count in stock, im not sure why itll work once, but it wont work over each iteration.
code:
/**
* @description This function removes a deck from the database, and re-seeds whatever cards where in that deck
* back into the sellable stock
*
* @route DELETE /api/deck/:deckId
* @param deckId ObjectID of the deck
* @comment hitting this route will change the countInStock value of the {product}
* in the database by whatever cards where in the [deck.cards]
*
*/
module.exports = asyncHandler(async (req, res) => {
try {
// find the deck
const deck = await Deck.findById(req.params.id);
// check if it exists
if (!deck) {
return res
.status(404)
.json({ message: `Deck: ${req.params.id} cannot be found` });
}
// we need to run a foreach command over every object in [deck.cards]
await deck.cards.forEach(async (c) => {
console.log(c);
// find the card
const card = await Card.findById(c._id);
// We then need to find the sellable { Product } and add back to it, so it can be sold/traded
const product = await Product.findById(card.productId);
// increase the amount of inStock sellable items, by 1.
await product.set({ countInStock: product.countInStock 1 });
await product.save();
// if we get here we want to remove the card object from the database, its just a placeholder.
await card.remove();
});
// remove the deck
await deck.remove();
res.status(200).json({ success: true });
} catch (error) {
console.error(error);
res.status(500).json({ message: `Server Error: ${error.message}` });
}
});
CodePudding user response:
I will try to describe the explanation given by @jfriend00 as much as possible.
Many including me thought that forEach
is a simplified version of the for
loop, but the truth is IT IS NOT
when it comes to the async await
. For example, let's take this code:
const loopThis = [1, 2, 3, 4];
function timeOut2000() {
return new Promise(resolve => setTimeout(resolve, 1000));
}
async function loopThrough() {
await loopThis.forEach(async x => {
await timeOut2000();
console.log(x)
});
}
loopThrough()
When running the above, we can see that it doesn't wait for the timeOut2000
on each loop, because it doesn't wait for each promise to resolve.
To achieve the async await
for each loop, we can use for
loop or for .. in ..
like below:
const loopThis = [1, 2, 3, 4];
function timeOut2000() {
return new Promise(resolve => setTimeout(resolve, 1000));
}
async function loopThrough() {
for (const x of loopThis) {
await timeOut2000();
console.log(x)
};
}
loopThrough()