belyid
belyid

Reputation: 871

Is it possible to execute nested queries with conditional promises in sequelize in a single transaction?

I'm trying to perform an update to a object with several relations. One of those relations is many to many and I use product.setCategories([categories]) to set/update them:

var p = req.product;
var cIds = [];

return models.sequelize.transaction(function (t) {
    var promises = [];
    //check if the product is supposed to have categories
    if (req.body.categories) {
        req.body.categories.forEach(function (c) {
            cIds.push(c.id);
        });
        promises.push(models.category.findAll({
            where: { id: { $in: cIds } },
            transaction: t
        }).then(function (categories) {
            p.setCategories(categories, { through: 'productsCategories' });
        }));
    } else if (p.categories.length > 0) {
        //delete existing categories
        promises.push(p.setCategories([], { transaction: t, through: 'productsCategories' }));
    }

    /add some more queries to "promises" and:
    return models.sequelize.Promise.all(promises);

}).then(function (result) {
    res.json(result);
}).catch(function (error) {
    respondError(res, error);
});

I was trying to do that in a single transaction ("t") but I can't see how since I need a nested query that is executed only after retrieving categories from database.

Can I do it in a single transaction? Is this the best way to update manyToMany?

I'm using sequelize v3.23.3 with Postgres.

Upvotes: 1

Views: 922

Answers (1)

Jan Aagaard Meier
Jan Aagaard Meier

Reputation: 28798

return models.sequelize.transaction(function (t) {
    //check if the product is supposed to have categories
    if (req.body.categories) {
        req.body.categories.forEach(function (c) {
            cIds.push(c.id);
        });
        return models.category.findAll({
            where: { id: { $in: cIds } },
            transaction: t
        }).then(function (categories) {
            p.setCategories(categories);
        });
        // OR
        return p.setCategories(cIds)
    } else if (p.categories.length > 0) {
        //delete existing categories
        return p.setCategories([], { transaction: t, through: 'productsCategories' });
    }
});

If you are only doing a single action at a time - here you are either setting to an array or setting to nothing, you can simply return from each branch in the if statement, no need to end with .all. If you are on a fairly recent version of sequelize you can also simply pass the cIds directly to setCategories.

Upvotes: 1

Related Questions