Как перебрать различные запросы Sequelize с использованием транзакций - PullRequest
0 голосов
/ 27 августа 2018

В настоящее время я пытаюсь выполнить итерацию для массива объектов, которые необходимо вставить в зависимости от количества элементов в массиве (из request.body).

Ожидаемое поведение:

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

-

Фактическое поведение:

Фактическое поведение заключается в том, что в базу данных вставляется только последний элемент массива, а первый перезаписывается и не вставляется в базу данных.

-

Мой вопрос:

Как изменить эту существующую логику, чтобы иметь возможность вставлять несколько записей в базу данных при использовании транзакций / секвелирования SQL-запросов?

Данные, которые я отправляю в запрос API:

[{
  "venue_id": 5,
  "event_id": 13,
  "table_id": 4,
  "date_in": "2017-11-30",
  "date_out": "2017-12-31",
  "check_in": "2017-12-31T17:04:42.333Z",
  "check_out": "2017-12-31T17:05:42.333Z"
},
{
  "venue_id": 6,
  "event_id": 18,
  "table_id": 6,
  "date_in": "2017-11-30",
  "date_out": "2017-12-31",
  "check_in": "2017-12-31T17:04:42.333Z",
  "check_out": "2017-12-31T17:05:42.333Z"
}]

Логика вызовов API приведена ниже. Этот запрос API в основном выполняет следующие действия:

  1. Запускает транзакцию SQL для фиксации или отката в случае сбоя.
  2. Выполняет поиск идентификатора места проведения, идентификатора клиента и идентификатора таблицы. (на случай, если кто-то попытается вставить несколько несуществующих идентификаторов)
  3. Рассчитывает стоимость столов вместе
  4. Создает бронирование
  5. Подтверждает транзакцию и возвращает ответ.
router.post(
  "/api/v1/reservations",
  [passport.authenticate("jwt", { session: false }), isCustomer],
  (request, response) => {

    return models.sequelize.transaction().then(t => {


      // I was trying to do this by using a for loop but it doesn't seem to work.

      for (var i = 0; i < request.body.length; i++) {

        return models.Venue.findById(request.body[i].venue_id)
          .then(venue => {
            return models.Customer.findById(request.customer.id);
          })
          .then(customer => {
            return models.Table.findAllById(request.body[i].table_id);
          })
          .then(tables => {
            var price = 0;

            for (var i = 0; i < tables.length; i++) {
              price = price + tables[i].price;
            }

            return models.Reservation.createReservation(
              request.body[i],
              price,
              request.customer.id
            ).then(reservation => {
              return reservation.addTables(tables).then(() => {
                if (request.body.length - 1 === i) {
                  t.commit().then(() => {
                    return response.status(200).send(reservation);
                  });
                }
              });
            });
          })
          .catch(error => {
            console.log(error);
            t.rollback().then(() => {
              return response.status(error.status_code).send(error.message);
            });
          });
      }
    });
  }

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Вместо использования цикла for я использовал цикл foreach. Кажется, что после некоторых небольших корректировок он работает.

0 голосов
/ 27 августа 2018

Вы сделали ваш код таким сложным и достигли ситуации обратного вызова , я бы предложил использовать aysnc await :

Здесь я попытался получить почти безошибочный код от вашего, но все же ваш код выглядит сложным, пожалуйста, попробуйте решить, если есть какие-либо ошибки. Но вот того, чего вы можете достичь, ожидаете:

router.post(
"/api/v1/reservations", [passport.authenticate("jwt", {
    session: false
}), isCustomer],
(request, response) => {

    return models.sequelize.transaction().then(async (t) => { // <--- ASYNC

        // I was trying to do this by using a for loop but it doesn't seem to work.

        for (var i = 0; i < request.body.length; i++) {

            try{
                let venue = await models.Venue.findById(request.body[i].venue_id) // <--- AWAIT
                let customer = await models.Customer.findById(request.customer.id); // <--- AWAIT
                let tables = await models.Table.findAllById(request.body[i].table_id); // <--- AWAIT
                let price = 0;

                for (var i = 0; i < tables.length; i++) {
                    price = price + tables[i].price;
                }

                let reservation = await models.Reservation.createReservation(
                    request.body[i],
                    price,
                    request.customer.id
                ); // <--- AWAIT   
                await reservation.addTables(tables); // <--- AWAIT
                if (request.body.length - 1 === i) {
                    await t.commit();
                    // return response.status(200).send(reservation); 
                }
            } catch (err) {
                await t.rollback();
                return response.status(error.status_code).send(error.message);
            }
        }

    });
}

Надеюсь, это поможет вам получить то, что вы хотите:)


Реальное поведение таково, что только последний элемент в массиве вставляется в базу данных и первый перезаписывается, а не вставляется в базу данных.

Причина : Асинхронное поведение, ищите в вашем первом цикле, оно будет выполняется независимо от того, выполняется ваш внутренний код или нет, так что он будет сначала переберите все request.body, а затем ваш внутренний код начало выполнения, это называется цикл обработки событий

...