Yogendra
Yogendra

Reputation: 107

Getting data executes before insertion

I am trying to insert data in MySQL using Knex inside the loop first, and then want to get the data. But, getting the data executes first before the insertion. May someone please help me in doing this?

for (let i = 0; i < fileArray.length; i++) {
  fileLocation = fileArray[i].location;
  imgLocationArray.push(fileLocation);
  knex("files")
    .insert({
      fileLink: fileLocation,
      todoId: todoId,
      userId: userId
    })
    .then(() => {
      console.log("phle chala!");
    })
    .catch(err => console.log(err));
}

knex("files")
  .where("files.userId", userId)
  .then(userFiles => {
    console.log("baad wala hai yrr");
    res.json({
      userFiles: userFiles
    });
  })
  .catch(err => console.log(err));

Upvotes: 1

Views: 141

Answers (1)

Rich Churcher
Rich Churcher

Reputation: 7654

When using promises (as Knex queries do) JavaScript will continue straight onto the next statement without waiting for the previous one to finish. This is what you're encountering here: your code starts all the database inserts, but does not wait for them to finish before issuing the query to get back the data.

Because you're iterating over a series of files, Promise.all is an ideal candidate for a solution. Here's how it works. First, we collect up all the promises:

const insertions = fileArray.map(file => {
  fileLocation = fileArray[i].location;
  imgLocationArray.push(fileLocation);
  return knex("files")
    .insert({
      fileLink: fileLocation,
      todoId: todoId,
      userId: userId
    })
})

Note the return statement here, that's very important. Next, we wait for all those promises to finish:

  Promise.all(insertions)
    .then(() => knex("files").where("files.userId", userId))
    .then(userFiles => {
      console.log("baad wala hai yrr");
      res.json({
        userFiles: userFiles
      });
    })
    .catch(err => console.log(err));

Only in this final .then block can we depend on the data being available to us, because all the previous queries have finished.

If you happen to be working in an environment on your server where async/await is available (Node versions after 7.6) then you can do this:

try {
  await Promise.all(insertions);
  const userFiles = await knex("files").where("files.userId", userId);
  res.json({ userFiles });
} catch (e) {
  // Handle database error
}

Many people find this syntax more readable. Note that the function containing this code must be declared with the async keyword:

myExpressRouter.post("userfiles", async (req, res) => {
  // ...
})

Upvotes: 2

Related Questions