同步执行Sequelize查询

时间:2016-10-08 03:44:07

标签: javascript node.js postgresql asynchronous sequelize.js

我正在使用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"列表中填充了所有对象?

谢谢!

4 个答案:

答案 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 端点。

希望对遇到同样问题的人有所帮助。