如何使用事务遍历不同的Sequelize查询

时间:2018-08-27 10:59:01

标签: node.js promise sequelize.js

目前,我正在尝试对需要插入的对象数组进行迭代,具体取决于数组中项的数量(来自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. 搜索场所ID,客户ID和TableId。 (以防有人尝试插入一些不存在的ID)
  4.   
  5. 一起计算表的价格
  6.   
  7. 创建预订
  8.   
  9. 提交事务并返回响应。
  10.   
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 :(得分:1)

您已经使代码看起来如此复杂,并且遇到了 callback hell 的情况,我建议使用 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);
            }
        }

    });
}
  

希望这将帮助您获得想要的东西:)


  

实际行为是只有数组中的最后一项是   插入数据库,第一个被覆盖而不是   被插入数据库。

     

原因:是异步行为,请在第一个for循环中查看,它将   无论您的内部代码是否执行,都将被执行,因此它将   首先遍历所有request.body,然后您的内部代码将   开始执行,这称为 event loop

答案 1 :(得分:0)

我使用了foreach循环,而不是使用for循环。经过一些小的调整后,它似乎可以正常工作。