简体   繁体   中英

Node.js Sequalize creating new rows in forEach loop

I'm trying to create new rows in the database using Sequalize ORM. I receive an array of collections from req.query.collections . For each of those collections I need to create a new userCollection . If none userCollection s were created, I wanna respond with internal server error (line 41), otherwise return an array of objects with newly created userCollections .

The problem is, I keep getting an internal server error when I make test requests from Postman. When I check my database, I see that those userCollections were created, so no error occurred.

I know why this happens: because userCollection.build({ stuff }).save() returns a promise. So when I try to console.log userCollections from within .then() statement, I get an array with a newly created collections, just like I should. But by that time server has already responded with internal server error.

Here's my function code:

exports.addCollections = async (req, res, next) => {
    const libraryId = req.params.libraryId;
    const collections = req.query.collections;

    if (!collections)
        next(Boom.forbidden());

    const userCollections = [];

    collections.forEach(async (collectionId, index) => {
        const collection = await Collection.findByPk(collectionId);

        if (!collection)
            return next(Boom.notFound());

        userCollection.build({
            user_id: req.user.id,
            library_id: libraryId,
            public_collection_id: collection.id,
            title: collection.title,
            description: collection.description
        })
            .save()
            .then(newUserCollection => {
                userCollections.push(newUserCollection.get({ plain: true }));

                // should be printed first, but comes second
                // prints out the array with newly created record
                console.log(userCollections);
            })
            .catch(error => {
                console.log(error);
            });
    });

    // should be printed second, but comes first
    // prints out empty array
    console.log(userCollections);

    if (userCollections.length === 0) {
        next(Boom.internal());
    }

    res.json(userCollections);
}

Posting the solution

Thanks to Sebastien Chopin who created this tutorial: https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404

So I added this function:

const asyncForEach = async (array, callback) => {
    for (let index = 0; index < array.length; index++) {
        await callback(array[index], index, array)
    }
}

And instead of collections.forEach...(blah blah) (line 10 of the code posted in the question) I do:

try {
    await asyncForEach(collections, async (collectionId, index) => {
        const collection = await Collection.findByPk(collectionId);

        if (!collection)
            return next(Boom.notFound());

        userCollection.build({
            user_id: req.user.id,
            library_id: libraryId,
            public_collection_id: collection.id,
            title: collection.title,
            description: collection.description
        })
            .save()
            .then(newUserCollection => {
                userCollections.push(newUserCollection.get({ plain: true }));
                console.log(userCollections);
            })
            .catch(error => {
                console.log(error);
            });
    })
} catch (err) {
    return next(Boom.internal(err.message));
}

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