Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute Sequelize queries synchronously

I am building a website using Node.js and Sequelize (with a Postgres backend). I have a query that returns many objects with a foreign key, and I want to pass to the view a list of the objects that the foreign key references.

In the example, Attendances contains Hackathon keys, and I want to return a list of hackathons. Since the code is async, the following thing of course does not work in 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});
});

Is there any way to do that query in a synchronous way, meaning that I don't return the view untill I have the "hacks" list filled with all the objects?

Thanks!

like image 374
Paul Avatar asked Oct 08 '16 03:10

Paul


2 Answers

Use Promise.all to execute all of your queries then call the next function.

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
        });
      })
});
like image 116
synthet1c Avatar answered Oct 05 '22 09:10

synthet1c


The Sequelize library has the include parameter which merges models in one call. Adjust your where statement to bring the Hackathons model into Attendance. If this does not work, take the necessary time to setup Sequelize correctly, their documentation is constantly being improved. In the end, you'll save loads of time by reducing error and making your code readable for other programmers.

Look how much cleaner this can be...

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)
})

Also..

Hackathon.belongsTo(Attendance)
Attendance.hasMany(Hackathon)
sequelize.sync().then(() => {
  // this is where we continue ...
})

Learn more about Sequelize includes here: http://docs.sequelizejs.com/en/latest/docs/models-usage/

like image 22
buycanna.io Avatar answered Oct 05 '22 11:10

buycanna.io