Will Kanga
Will Kanga

Reputation: 742

node.js sqlite3 run something after all db.each async callbacks finish

Can I run something after every row has been processed by db.each?

var email = openEmailConnection();
db.each("SELECT * FROM mytable", async (err, row) => {
  var x = await makeNetworkApiCall();
  await email.sendMail({message: "your message: " + x});
  console.log("finished");
});
//somehow call closeEmailConnection() after all async callbacks have finished

I don't want to do db.all because that loads everything onto memory. Maybe I could do something with promises and Promise.all?

Upvotes: 1

Views: 1177

Answers (2)

Gert Rikkers
Gert Rikkers

Reputation: 86

Maybe you could use an anonymous callback function. I used a similar construction to add rows to an array and returning that array after all callbacks of the rows are completed:

select = (db, tableName) => {
  const rows = [];
  return new Promise((resolve, reject) => {
    const sql = `SELECT * FROM ${tableName}`
    db.each(sql, (err, row) => {
      if (err) {
        console.error(err.message);
      }
      rows.push(row);
    }, () => {
      resolve(rows);
    });
  })
}

For your code this would be something like this:

const email = openEmailConnection();
db.each("SELECT * FROM mytable", async (err, row) => {
  var x = await makeNetworkApiCall();
  await email.sendMail({message: "your message: " + x});
  console.log("finished");
}, () => { 
   closeEmailConnection();
});

Upvotes: 1

Sirko
Sirko

Reputation: 74046

Maybe as an alternative, I suggest to use better-sqlite3 instead. Here, you have an iterate() function that allows you to process all entries in a for loop like this (from their docu, slightly adapted):

const email = openEmailConnection();

const stmt = db.prepare('SELECT * FROM mytable');
for (const entry of stmt.iterate()) {
  const x = await makeNetworkApiCall();
  await email.sendMail({message: "your message: " + x});
}

closeEmailConnection();

Upvotes: 1

Related Questions