【问题标题】:How to loop over different Sequelize queries using transactions如何使用事务循环不同的 Sequelize 查询
【发布时间】:2019-02-01 21:38:31
【问题描述】:

目前,我正在尝试对需要插入的对象数组进行迭代,具体取决于数组中的项目数(来自 request.body)。

预期行为:

我认为 for 循环会导致不同的 sequelize SQL 查询,这些查询将一个接一个地插入到数据库中。

--

实际行为:

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

--

我的问题:

如何改变这个现有的逻辑,以便能够在使用事务/sequelize 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. 搜索场所 ID、客户 ID 和表格 ID。 (以防有人试图插入一些不存在的 id)
  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);
            });
          });
      }
    });
  }

【问题讨论】:

    标签: node.js promise sequelize.js


    【解决方案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

    【讨论】:

    • 干杯,我已经设法修复它。我会尽快更新我的答案!
    【解决方案2】:

    我没有使用 for 循环,而是使用了 foreach 循环。经过一些小的调整后,它似乎工作了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-07-07
      • 2020-05-12
      • 2019-11-09
      • 2018-08-17
      • 2022-09-30
      • 2023-03-04
      • 2012-05-09
      • 1970-01-01
      相关资源
      最近更新 更多