it-roy-ru.com

Использование циклов и обещаний в транзакциях в Sequelize

В настоящее время я создаю приложение Nodejs, Express, Sequelize (w. PostgreSQL) и столкнулся с несколькими проблемами при использовании обещаний вместе с транзакциями и циклами.

Я пытаюсь выяснить, как использовать циклы for в транзакции. Я пытаюсь перебрать список участников и создать нового пользователя в базе данных для каждого из них. 

Я знаю, что следующий код неверен, но он показывает, что я пытаюсь сделать.

Может кто-то указать мне верное направление?

        var members = req.body.members;
        models.sequelize.transaction(function (t) {
            for (var i = 0; i < members.length; i++) {
                return models.User.create({'firstname':members[i], 'email':members[i], 'pending':true}, {transaction: t}).then(function(user) {
                    return user.addInvitations([group], {transaction: t}).then(function(){}).catch(function(err){return next(err);});
                })
            };
        }).then(function (result) {
            console.log("YAY");
        }).catch(function (err) {
            console.log("NO!!!");
            return next(err);
        });
13
ReturnToZero

Вы должны использовать Promise.all

    var members = req.body.members;
    models.sequelize.transaction(function (t) {
        var promises = []
        for (var i = 0; i < members.length; i++) {
            var newPromise = models.User.create({'firstname':members[i], 'email':members[i], 'pending':true}, {transaction: t});
           promises.Push(newPromise);
        };
        return Promise.all(promises).then(function(users) {
            var userPromises = [];
            for (var i = 0; i < users.length; i++) {
                userPromises.Push(users[i].addInvitations([group], {transaction: t});
            }
            return Promise.all(userPromises);
        });
    }).then(function (result) {
        console.log("YAY");
    }).catch(function (err) {
        console.log("NO!!!");
        return next(err);
    });

Я не верю, что вам нужно catch внутри транзакций сиквелиза, так как я думаю, что это ускользает от улова транзакции 

Извините за форматирование. На мобильный. 

Promise.all будет ждать всех обещаний, которые будут возвращены (или не выполнены) перед запуском .then, а обратный вызов .then будет представлять все данные обещаний из каждого массива 

27
Datsik

Вам нужно использовать встроенные циклические конструкции bluebird, которые поставляются с sequelize:

var members = req.body.members;
models.sequelize.transaction(t => 
  Promise.map(members, m => // create all users
    models.User.create({firstname: m, email: m, 'pending':true}, {transaction: t})
  ).map(user => // then for each user add the invitation
     user.addInvitations([group], {transaction: t}) // add invitations
)).nodeify(err); // convert to node err-back syntax for express
5
Benjamin Gruenbaum

В зависимости от вашей реализации Node.js это может помочь. У меня такая же настройка с использованием экспресс, POSTGRES и sequelize.

Лично я предпочел бы реализацию async/await (ES6), а не/catch, так как ее легче читать. Кроме того, создание функции, которую можно вызывать извне, улучшает возможность повторного использования.

async function createMemeber(req) {
let members = req.body.members;
  for (var i = 0; i < members.length; i++) {
    // Must be defined inside loop but outside the try to reset for each new member;
    let transaction = models.sequelize.transaction();
    try { 
      // Start transaction block.
      let user = await models.User.create({'firstname':members[i],  'email':members[i], 'pending':true}, {transaction});
      await user.addInvitations([group], {transaction}));

      // if successful commit the record. Else in the catch block rollback the record.
      transaction.commit();
      // End transaction block.
      return user;
    } catch (error) { 
      console.log("An unexpected error occurred creating user record: ", error);
      transaction.rollback();
      // Throw the error back to the caller and handle it there. i.e. the called express route.
      throw error;
    }
  }
}
1
Ryan

Сначала: https://caolan.github.io/async/docs.html

Так легко:

// requiring...
const async = require('async');

// exports...
createAllAsync: (array, transaction) => {
  return new Promise((resolve, reject) => {
    var results = [];
    async.forEachOf(array, (elem, index, callback) => {
      results.Push(models.Model.create(elem, {transaction}));
      callback();
    }, err => {
      if (err) {
        reject(err);
      }
      else {
        resolve(results);
      }
    });
  });
}
0
Eri Jonhson