I would like to delete records from multiple table one after another. Under a single router, how could I call the following destroy functions one after another
function deleteFromTable1(param1, transaction) {
return table1_model.destroy({
where: { param1 },
transaction
});
}
function deleteFromTable2(param1, transaction) {
return table2_model.destroy({
where: { param1 },
transaction
});
}
function deleteFromTable3(param1, transaction) {
return table2_model.destroy({
where: { param1 },
transaction
});
}
When you say
Under a single router
I am assuming you have a setup similar to a Node.js and Express.js application where your route and handler look like the following:
app.post('/delete', function (req, res) {
// delete some items from database
})
In this case, you could do the following:
function deleteItems(req, res) {
// since Sequelize `destroy` calls return promises,
// you can just wrap all of them in `Promise.all`
// and "wait" for all of them to `resolve` (complete)
const handleSuccessfulDeletion = () => {
res.status(200).json({
status: 200,
message: 'OK'
})
}
const handleError = (error) => {
// ...
}
Promise.all([
deleteFromTable1(param1, transaction),
deleteFromTable2(param1, transaction),
deleteFromTable3(param1, transaction)
])
.then(handleSuccessfulDeletion)
.catch(handleError)
}
app.post('/delete', deleteItems)
This way, all deletion calls get completed before you return the success response.
Alternatively, if you need to your call need to be sequential, then you could do the following:
function deleteItems(req, res) {
const handleSuccessfulDeletion = () => {
// ...
}
const handleError = (error) => {
// ...
}
deleteFromTable1(param1, transaction)
.then(() => deleteFromTable2(param1, transaction))
.then(() => deleteFromTable3(param1, transaction))
.then(handleSuccessfulDeletion)
.catch(handleError)
}
app.post('/delete', deleteItems)
Here's an example - jsbin.com
Related
I have created the following function that makes a call to a third party API to create an order and on the response iam calling model function that checks if a user with the user ID exits or not and some operation is done accordingly.
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(response => {
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}
Iam getting the following error in node console :
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
^^^^^
SyntaxError: await is only valid in async function
Can anybody please point out what is wrong here
You can't await some expression inside a function which is not async. Just use async function inside then.See more about await here
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(async(response) => { //change here
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}
On the following post method, I'm having some issues due to moongose async. res.send(suggestions) is executed first then Expense.findOne.exec
app.post('/suggestions', async function(req, res) {
const suggestions = await req.body.map((description) => {
Expense.findOne({ description: new RegExp(description, 'i') }).exec((err, result) => {
if (result) {
console.log(result.newDescription);
return {
description,
newDescription: result.newDescription,
category: result.category,
subcategory: result.subcategory
};
}
});
});
res.send(suggestions);
});
The result is a array of null values. How can I executed a query for each item, then execute res.send(suggestion)?
Found solution with the following code:
app.post('/suggestions', async function(req, res) {
try {
if (req.body.length > 0) {
const suggestions = req.body.map((description) =>
Expense.findOne({ description: new RegExp(description, 'i') })
);
const results = await Promise.all(suggestions);
return res.send(results);
}
} catch (e) {
console.log('error', e);
}
});
I want to refactor code for chain of promises by async, await. I have sequelize ORM for DB management and the code is written in AWS Lambda function having multiple middleware. In such cases I have to traverse code for multiple entries using sequelize transactions. It is easy to manage using promise.all() but need to change it to async await syntax for cleaner code.
Here are my demo code.
/* get all invoice where user_id === current logged in user, and where status != "paid" */
db.Invoice.findAll({
where: {
user_id: currentLoggedInUser,
status: {
$ne: "paid"
}
}
}).then(invoices => {
if (!invoices || invoices === null) {
return false;
}
function addScheduledTransactionAttempts(invoice, tryPayOnDate, t) {
return new Promise((resolve, reject) => {
/* check If any ScheduledTransactionAttempts exists for this invoice.id */
db.ScheduledTransactionAttempts.find({
where: {
invoice_id: invoice.id
}
})
.then(function(attempts) {
if (attempts) {
attempts
.destroy({}, {
transaction: t
})
.then(deletedAttempts => {
console.log("Attempts Record Deleted: ", deletedAttempts);
})
.catch(error => {
reject(error);
t.rollback();
});
}
return db.ScheduledTransactionAttempts.create({
invoice_id: invoice.id,
payment_source_id: PaymentMethodId,
try_pay_on_date: tryPayOnDate,
stripe_customer_id: currentLogInStripeCustomerId
}, {
transaction: t
})
.then(function(attempt) {
resolve(attempt.id);
})
.catch(error => {
reject(error);
t.rollback();
});
})
.catch(error => {
reject(error);
t.rollback();
});
});
}
//Run transaction to addScheduledTransactionAttempts
return db.sequelize.transaction().then(function(t) {
let promiseArr = [];
var i = 0;
invoices.forEach(function(invoice) {
var schedulePaymentDate = moment(paymentDate);
if (invoice) {
let tryPayOnDate = schedulePaymentDate
.add(i, "month")
.format("YYYY-MM-DD");
promiseArr.push(
addScheduledTransactionAttempts(invoice, tryPayOnDate, t) //calling above function
);
i++;
}
});
//now execute promise all
Promise.all(promiseArr)
.then(function(result) {
t.commit();
return true;
})
.catch(function(err) {
t.rollback();
return false;
});
});
});
In the above code I want to change
Promise.all(promiseArr)
which is calling
addScheduledTransactionAttempts
function to do DB queries to simple async function await process to make it easy simpler understandable without having multiple .then or .then inside then promises.
Any help regarding would be appreciated,
Thanks.
It's quite simple. await is valid when invoking methods that return a Promise. All of your SDK methods already return a promise, so refactoring should be quite straight forward. Here's something to get you off ground:
const processInvoices = async currentLoggedInUser {
const invoices = await db.Invoice.findAll({
where: {
user_id: currentLoggedInUser,
status: {
$ne: 'paid',
},
},
});
if (yourOwnLogicForInvoicesObject) {
for (const invoice of invoices) {
const potentiallyFoundInvoice = await db.ScheduledTransactionAttempts.find({
where: {
invoice_id: invoice.id,
},
});
if (potentiallyFoundInvoice) {
await addScheduledTransactionAttempts(potentiallyFoundInvoice)
}
}
}
}
const addScheduledTransactionAttempts = async invoice => {
console.log('Do something with your invoice', invoice)
}
Long story short: refactor the code inside your functions into smaller functions and make these new functions async, just like I did with addScheduledTransactionAttempts and processInvoices
More on async/await
I have a cloud function that runs 3 firestore queries in 3 different collections. Each query has a foreach loop inside the then block and after the foreach loop it performs an update in a collection. Here is the code:
const someDocRef
const someDocRef2
const someDocRef3
db.collection("someOtherCollection").get().then(results=> {
results.forEach(result=> {
//do some work
})
someDocRef.update(....);
})
db.collection("someOtherCollection2").get().then(results=> {
results.forEach(result=> {
//do some work
})
someDocRef2.update(....);
})
db.collection("someOtherCollection3").get().then(results=> {
results.forEach(result=> {
//do some work
})
someDocRef3.update(....);
})
res.status(200).send("I waited for all the Queries AND the update operations inside the then blocks of queries to finish!");
So how can I return the response after all the operations finish?
If you call some asynchronous Firestore methods in your Cloud Function (like get() for a CollectionReference or update() for a DocumentReference) you just have to chain the different promises returned by those methods.
So, based on the code of your question you could modify it as follows:
const someDocRef
const someDocRef2
const someDocRef3
db.collection("someOtherCollection").get()
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef.update(....);
})
.then(() => {
return db.collection("someOtherCollection2").get();
})
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef2.update(....);
})
.then(() => {
return db.collection("someOtherCollection3").get();
})
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef3.update(....);
})
.then(() => {
res.status(200).send("I waited for all the Queries AND the update operations inside the then blocks of queries to finish!");
})
Note that this will work because the number of someCollectionRefs and someDocRefs is known upfront. In case you have a variable number of asynchronous operations to execute, you will need to use the Promise.all() method, as suggested in the other answers.
In case the 3 blocks
db.collection("someOtherCollectionX").get()
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRefX.update(....);
})
can be executed totally separately (i.e. each block results does not impact the other blocks), you can parallelize the calls as follows:
const someDocRef
const someDocRef2
const someDocRef3
const p1 = db.collection("someOtherCollection").get()
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef.update(....);
});
const p2 = db.collection("someOtherCollection2").get()
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef2.update(....);
});
const p3 = db.collection("someOtherCollection3").get()
.then(results => {
results.forEach(result=> {
//do some work
})
return someDocRef3.update(....);
});
Promise.all([p1, p2, p3])
.then(() => {
res.status(200).send("I waited for all the Queries AND the update operations inside the then blocks of queries to finish!")
});
If you do not want to make your function an async function you could do something like this:
const someCollectionRef
const someCollectionRef2
const someCollectionRef3
const promise1 = db.collection("someOtherCollection").get().then(results=> {
results.forEach(result=> {
//do some work
})
someCollectionRef.update(....);
})
const promise2 = db.collection("someOtherCollection2").get().then(results=> {
results.forEach(result=> {
//do some work
})
someCollectionRef2.update(....);
})
const promise3 = db.collection("someOtherCollection3").get().then(results=> {
results.forEach(result=> {
//do some work
})
someCollectionRef3.update(....);
})
Promise.all([promise1, promise2, promise3])
.then(_ => res.status(200).send("I waited for all the Queries AND the update operations inside the then blocks of queries to finish!"));
Maybe you could use Promise.all to chain the promises. Promise.all MDN
Promise Demo from MDN:
var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
// expected output: Array [3, 42, "foo"]
To overcome callback hell in javascript, I'm trying to use async await from legacy code written in SQLServer procedure.
But I'm not sure my code might be write properly.
My first confusing point is when async function returns, should it return resolve() as boolean, or just return reject and handle with try-catch?
Here is my code snippets.
Please correct me to right direction.
apiRoutes.js
app.route('/api/dansok/cancelDansok')
.post(dansokCancelHandler.cancelDansok);
dansokCancelController.js
const sequelize = models.Sequelize;
const jwt = require('jsonwebtoken');
async function jwtAccessAuthCheck(accessToken) {
if (!accessToken) {
return Promise.reject('Empty access token');
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
return Promise.reject('TokenExpiredError.');
} else {
return Promise.resolve();
}
});
}
async function checkFeeHist(dansokSeqNo) {
let feeHist = await models.FeeHist.findOne({
where: { DansokSeqNo: dansokSeqNo}
});
return !!feeHist;
}
async function getNextDansokHistSerialNo(dansokSeqNo) {
....
}
async function getDansokFee(dansokSeqNo) {
....
}
async function doCancel(dansokSeqNo) {
try {
if (await !checkFeeHist(dansokSeqNo)) {
log.error("doCancel() invalid dansokSeqNo for cancel, ", dansokSeqNo);
return;
}
let nextDansokSerialNo = await getNextDansokHistSerialNo(dansokSeqNo);
await insertNewDansokHist(dansokSeqNo, nextDansokSerialNo);
await updateDansokHist(dansokSeqNo);
await updateVBankList(dansokSeqNo, danokFee.VBankSeqNo);
await getVBankList(dansokSeqNo);
} catch (e) {
log.error("doCancel() exception:", e);
}
}
exports.cancelDansok = function (req, res) {
res.setHeader("Content-Type", "application/json; charset=utf-8");
const dansokSeqNo = req.body.DANSOKSEQNO;
const discKindCode = req.body.HISTKIND;
const worker = req.body.PROCWORKER;
const workerIp = req.body.CREATEIP;
const accessToken = req.headers.accesstoken;
//check input parameter
if (!dansokSeqNo || !discKindCode || !worker || !workerIp) {
let e = {status:400, message:'params are empty.'};
return res.status(e.status).json(e);
}
try {
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
doCancel(dansokSeqNo).then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
});
});
} catch(e) {
return res.status(e.status).json(e);
}
};
You'll need to rewrite jwtAccessAuthCheck(accessToken) so that it keeps track of the outcome of its nested tasks. In the code you've written:
// Code that needs fixes!
async function jwtAccessAuthCheck(accessToken) {
// This part is fine. We are in the main async flow.
if (!accessToken) {
return Promise.reject('Empty access token');
}
// This needs to be rewritten, as the async function itself doesn't know anything about
// the outcome of `jwt.verify`...
jwt.verify(accessToken,"dipa",function(err){
if(err) {
// This is wrapped in a `function(err)` callback, so the return value is irrelevant
// to the async function itself
return Promise.reject('TokenExpiredError.');
} else {
// Same problem here.
return Promise.resolve();
}
});
// Since the main async scope didn't handle anything related to `jwt.verify`, the content
// below will print even before `jwt.verify()` completes! And the async call will be
// considered complete right away.
console.log('Completed before jwt.verify() outcome');
}
A better rewrite would be:
// Fixed code. The outcome of `jwt.verify` is explicitly delegated back to a new Promise's
// `resolve` and `reject` handlers, Promise which we await for.
async function jwtAccessAuthCheck(accessToken) {
await new Promise((resolve, reject) => {
if (!accessToken) {
reject('Empty access token');
return;
}
jwt.verify(accessToken,"dipa",function(err){
if(err) {
reject('TokenExpiredError.');
} else {
resolve();
}
});
});
// We won't consider this async call done until the Promise above completes.
console.log('Completed');
}
An alternate signature that would also work in this specific use case:
// Also works this way without the `async` type:
function jwtAccessAuthCheck(accessToken) {
return new Promise((resolve, reject) => {
...
});
}
Regarding your cancelDansok(req, res) middleware, since jwtAccessAuthCheck is guaranteed to return a Promise (you made it an async function), you'll also need to handle its returned Promise directly. No try / catch can handle the outcome of this asynchronous task.
exports.cancelDansok = function (req, res) {
...
jwtAccessAuthCheck(accessToken)
.then(() => {
log.info("jwt success");
return doCancel(dansokSeqNo);
})
.then(() => {
log.info("cancelDansok() finish");
res.status(200).json({ message: 'cancelDansok success.' });
})
.catch(e => {
res.status(e.status).json(e);
});
};
I strongly suggest reading a few Promise-related articles to get the hang of it. They're very handy and powerful, but also bring a little pain when mixed with other JS patterns (async callbacks, try / catch...).
https://www.promisejs.org/
Node.js util.promisify