我正在使用Node.js和Sequelize(使用Postgres后端)构建一个网站。我有一个查询,返回许多带有外键的对象,我想传递一个外键引用的对象列表。
在示例中,Attendances包含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"列表中填充了所有对象?
谢谢!
答案 0 :(得分:5)
使用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
});
})
});
答案 1 :(得分:2)
Sequelize库具有 include 参数,该参数在一次调用中合并模型。调整where语句以将 Hackathons 模型带入出勤。如果这不起作用,请花费必要的时间正确设置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/
答案 2 :(得分:0)
<强>立即调用异步函数表达强>
这是在 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 上测试。
答案 3 :(得分:-1)
在异步函数中使用 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 端点。
希望对遇到同样问题的人有所帮助。