繁体   English   中英

同步执行 Sequelize 查询

[英]Execute Sequelize queries synchronously

我正在使用 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”列表填满所有对象之前,我不会返回视图?

谢谢!

使用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 }); }) });

Sequelize 库具有包含参数,可在一次调用中合并模型。 调整您的 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/

立即调用异步函数表达式

这是在以下内容中提到的技术之一: 如何在顶层使用 async/await? 顶层 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 上测试。

在异步函数中使用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 端点。

希望这会帮助任何遇到同样问题的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM