同步执行 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 查询的主要内容,如果未能解决你的问题,请参考以下文章

使用 sequelize 通过相同两个表之间的单独联结表进行查询

在 Sequelize 中限制延迟加载的关联

node开发

建立Model

sequelize.query() 两次返回相同的结果

是否可以使用 Graphql 和 Sequelize 进行多租户?