同步执行 Sequelize 查询
Posted
技术标签:
【中文标题】同步执行 Sequelize 查询【英文标题】:Execute Sequelize queries synchronously 【发布时间】:2017-02-17 02:45:13 【问题描述】:我正在使用 Node.js 和 Sequelize(带有 Postgres 后端)构建一个网站。我有一个查询,它返回许多带有外键的对象,我想将外键引用的对象列表传递给视图。
在示例中,Attendances 包含 Hackathon 密钥,我想返回一个 Hackathon 列表。既然代码是异步的,那么下面的东西在Node中当然是行不通的:
models.Attendance.findAll(
where:
UserId: req.user.id
).then(function (data)
var hacks = [];
for (var d in data)
models.Hackathon.findOne(
where:
id: data[d].id
).then(function (data1)
hacks.append(data1);
);
res.render('dashboard/index.ejs', title: 'My Hackathons', user: req.user, hacks: hacks);
);
有没有办法以同步方式进行该查询,这意味着我不会返回视图,直到我将“hacks”列表填满所有对象?
谢谢!
【问题讨论】:
你尝试过带瀑布的异步模块吗?可以帮助你 在循环中查找一条记录是一种糟糕的设计。它应该只是一个查询。 【参考方案1】:使用Promise.all
执行所有查询,然后调用下一个函数。
models.Attendance.findAll(
where:
UserId: req.user.id
).then(function (data)
// get an array of the data keys, (not sure if you need to do this)
// it is unclear whether data is an object of users or an array. I assume
// it's an object as you used a `for in` loop
const keys = Object.keys(data)
// map the data keys to [Promise(query), Promise(query), ...]
const hacks = keys.map((d) =>
return models.Hackathon.findOne(
where:
id: data[d].id
)
)
// user Promise.all to resolve all of the promises asynchronously
Promise.all(hacks)
// this will be called once all promises have resolved so
// you can modify your data. it will be an array of the returned values
.then((users) =>
const [user1, user2, ...] = users
res.render('dashboard/index.ejs',
title: 'My Hackathons',
user: req.user,
hacks: users
);
)
);
【讨论】:
【参考方案2】:Sequelize 库具有 include 参数,可在一次调用中合并模型。调整您的 where 语句以将 Hackathons 模型引入 Attendance。如果这不起作用,请花必要的时间正确设置 Sequelize,他们的文档正在不断改进。最后,您将通过减少错误并使您的代码对其他程序员可读,从而节省大量时间。
看看这能有多干净......
models.Attendance.findAll(
include: [
model: Hackathon,
as: 'hackathon'
,
where:
UserId: req.user.id
).then(function (data)
// hackathon id
console.log(data.hackathon.id)
// attendance id
console.log(data.id)
)
还有..
Hackathon.belongsTo(Attendance)
Attendance.hasMany(Hackathon)
sequelize.sync().then(() =>
// this is where we continue ...
)
在此处了解有关 Sequelize 的更多信息: http://docs.sequelizejs.com/en/latest/docs/models-usage/
【讨论】:
你真的太安全了。如果您只是将所有内容都包装在 parseInt() 调用中,因为“也许”,那么您就是在培养货物。 @theraccoonbear - 更新代码,不需要 parseInt(),Sequelize 会在列指定为类型时处理:INTEGER【参考方案3】:立即调用异步函数表达式
这是How can I use async/await at the top level?Toplevel await 中提到的技术之一,可能很快就会在 2021 年推出,而且会更好。
最小的可运行示例:
const assert = require('assert');
const Sequelize, DataTypes = require('sequelize');
const sequelize = new Sequelize(
dialect: 'sqlite',
storage: 'db.sqlite',
);
const IntegerNames = sequelize.define(
'IntegerNames',
value: type: DataTypes.INTEGER, allowNull: false ,
name: type: DataTypes.STRING, ,
, );
(async () =>
await IntegerNames.sync(force: true)
await IntegerNames.create(value: 2, name: 'two');
await IntegerNames.create(value: 3, name: 'three');
await IntegerNames.create(value: 5, name: 'five');
// Fill array.
let integerNames = [];
integerNames.push(await IntegerNames.findOne(
where: value: 2
));
integerNames.push(await IntegerNames.findOne(
where: value: 3
));
// Use array.
assert(integerNames[0].name === 'two');
assert(integerNames[1].name === 'three');
await sequelize.close();
)();
在 Node v14.16.0、sequelize 6.6.2、seqlite3 5.0.2、Ubuntu 20.10 上测试。
【讨论】:
【参考方案4】:在异步函数中使用for of
models.Attendance.findAll(
where:
UserId: req.user.id
).then(async (data) =>
let hacks = []
for (const d of data)
const _hack = await models.Hackathon.findOne(
where:
id: data[d].id
)
hacks = [...hacks, _hack]
res.render('dashboard/index.ejs', title: 'My Hackathons', user: req.user, hacks: hacks)
)
这将在渲染之前等待 hacks 数组被填满。这应该适用于 API 端点。
希望这对遇到同样问题的人有所帮助。
【讨论】:
以上是关于同步执行 Sequelize 查询的主要内容,如果未能解决你的问题,请参考以下文章