目前,我正在尝试对需要插入的对象数组进行迭代,具体取决于数组中的项目数(来自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请求基本上执行以下操作:
- 启动SQL事务以便在出现错误时提交或回滚。
- 搜索venueId和CustomerId以及TableId。 (如果有人试图插入一些不存在的ID)
- 一起计算表的价格
- 创建预订
- 提交事务并返回响应。
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);
});
});
}
});
}
你已经使你的代码看起来如此复杂,你达到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
我没有使用for循环,而是使用了foreach循环。经过一些小的调整似乎有效。