简体   繁体   中英

How to update an array in MongoDB using mongoose?

I have two schemas, User, and Product. The User schema is where I store all the product ID and the number of items that the user added to the cart.

在此处输入图片说明

When the user makes a request to '/checkout' it should update the quantity and then remove it from the cart. I am having an issue when I checkout the quantity is not updating the quantity.

router.post('/checkout', auth, catchAsync(async (req, res) => {
    const user = await User.findById(req.session.userId);
    const err = [];
    if (user && user.products.length > 0) {

        user.products.map(async (product) => {
            let total = 0;
            const p = await Product.findById(product.productID);

            if (p.quantity > 0 && p.quantity > product.quantity) {
                console.log('IN');
                total = p.quantity - product.quantity;
                console.log(total);

                await Product.findOneAndUpdate({ _id: product.productID }, { $set: { quantity: total } });
            } else {
                err.push(`Item, ${p.name} is sold out`);
            }
        });
        await User.findOneAndUpdate({ _id: req.session.userId }, { $set: { products: [] } });
        if (err.length) {
            return res.status(500).json({ message: err });
        }
        return res.status(200).json({ message: 'OK' });
    }
    return res.status(200).json({ message: 'Empty cart' });
}));

User Schema:

在此处输入图片说明

Product Schema:

产品

I believe the problem in your code is at the user.products.map(...) function, because you never wait for all the promises you create in the map to resolve.

In other words, the map function returns an array of pending promises, but it will not wait for them to be done, and therefore the execution continues through the rest of the code reaching the res.status(...) before any of the code in map had been executed.

You have different options to solve it, but mainly you need to take care of the array of promises returned by the map function and wait for their completion, before you end your code. There is a very good explanation of how to handle this situation with async/await at Google Developers Web fundamentals guide .

I usually leverage Promise.all() function, which returns a single promise from the array of promises, and therefore you can wait until the code in map is executed in parallel for each item in the array (ie product in your case). You can read more about it at MDN documentation .

// ...

let promisesArray = user.products.map(async product => {...});
// promisesArray should look like: [Promise { <pending> }, Promise { <pending> }, … ]

// Using Promise.all we wait for each of them to be done in parallel
await Promise.all(promisesArray);

// Now you are certain the code in the map has been executed for each product

// ...

A good practice as well is to use try {} catch(err) {} block around the Promise.all() to handle cases of some promise being rejected.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM