how can I write a promise within another promise in async/await - javascript

I'm quite new to Node.js and I'm trying to build a pagination feature for my "Get all users" page in async/await. But I seem to have bumped into a hurdle and after an extensive research (both here, other sources and even tutorials), I still can't come up with a solution. All the solutions I've seen show me how to do either.
This is the code:
mongoOp.countDocuments({},function(err,totalCount) {
if(err) {
response = {"error" : true,"message" : "Error fetching data"}
}
mongoOp.find({},{},query,function(err,data) {
// Mongo command to fetch all data from collection.
if(err) {
response = {"error" : true,"message" : "Error fetching data"};
} else {
var totalPages = Math.ceil(totalCount / size)
response = {"error" : false,"message" : data,"pages": totalPages};
}
res.json(response);
});
});
I have figured out how to write both countDocuments() and find() functions in async/await to produce results as the following send correct json responses:
The countDocuments() function
try {
totalDocs = await mongoOp.countDocuments();
return res.status(200).json({totalDocs})
} catch (err) {
return res.send(err)
}
};
The find() query:
try {
const users = await mongoOp.find({}, {}, query);
return res.status(200).json({
status: users
});
} catch (error) {
return res.status(400).send(error);
}
However, I don't know how to put them together to produce the needed results.
I would be very grateful if I could be assisted.

You seem to be looking for
try {
const totalCount = await mongoOp.countDocuments();
const totalPages = Math.ceil(totalCount / size)
const data = await mongoOp.find({}, {}, query);
return res.status(200).json({"error":false, "message":data, "pages":totalPages});
} catch (err) {
return res.status(500).json({"error":true, "message":"Error fetching data"});
}

Related

React: TypeError Cannot read properties of undefined (reading '0')

I am working on a React App, and i'm trying to get some data using an axios GET request from my node backend.
the Api Endpoint i'm currently using that regard this problem is the following:
// NodeJS Backend
app.get('/v1/companys/user/:user_uuid', verify, (req, res) => { // GET - Company by User UUID
const selectQuery = 'SELECT * FROM companys WHERE uuid = (SELECT company_uuid FROM users WHERE uuid = ?)';
connection.query(selectQuery, [req.params.user_uuid], (err, results) => {
if(err) {
res.send(err)
} else if (results.length === 0) {
res.json({status: 404, message: 'Company not found'})
} else {
res.json({data: results})
}
});
});
This is my Front End:
// ReactJS FrontEnd
const companyLogo = userCompany ? userCompany.logo_url : null;
console.log(userCompany);
useEffect(() => {
const getUserCompany = async () => {
try {
await axios.get(process.env.REACT_APP_API_URL + 'companys/user/' + userUuid).then((response) => {
console.log("response "+ response);
let res = response.data.data[0];
console.log(res);
setUserCompany(res);
});
} catch (error) {
console.log(error);
}
};
getUserCompany();
}, [userUuid]);
There app works fine, but on the console the following error appear:
The object below the error is in fact the thing that i need (companyLogo)
I was wondering if someone know what am I doing wrong on my frontend to fix the TypeError.
Thanks for the help!
If you use optional chaining (?.) to catch possible null/undefined values, you'll most likely fix the issue.
So like this: let res = response.data.data?.[0];

No able to update data using react + express

I'm trying to update data from ui but data does not update though it can be done using postman and in payload data is also being passed.
Here is handle submit function:
enter code here
data.append("thingsTodo", values.thingsTodo);
data.append("minDaysToSpent", values.minDaysToSpent);
data.append("usp", values.usp);
data.append("geoRegion", values.geoRegion.value);
data.append("altitude", values.altitude);
data.append("thingsToConsider", values.thingsToConsider);
try {
const response = await axios.put(`/api/place/${id}`, data).then((data)=>console.log(data,"data"));
controller:
exports.updatePlace = async (req,res) => {
try {
let place = Place.findById(req.params.id)
if(!place){
return res.status(404).json({success:false,message:"Place does not exists"})
}
console.log(req.body)
place = await Place.findByIdAndUpdate(req.params.id,req.body,{new:true})
res.status(200).json({
success:true,
message:"Place Updated Successfully",
place
})
} catch (error) {
return res.status(500).json({
success:false,
error:error.message
})
}
}

I want to know how to got COUNT from SQL in reactjs

my request is good but i want to know how can i use my response in React.
SQL request :
```
exports.countAllComments = async (req, res) => {
const pId = req.params.id;
db.query(
"SELECT COUNT(*) FROM comments WHERE post_id = ?",
[pId],
(err, count) => {
if (err) {
res.status(500).json({ err });
console.log(err);
} else {
console.log(count)
res.status(200).json(count);
}
}
);
};
```
Front for fetch count:
```
const [countData, setCountData] = useState(0);
useEffect(() => {
const fetchCount = async () => {
try {
const fetchData = await Axios.get(
`http://localhost:3001/api/post/comment-count/${post.id}`,
{
headers: { Authorization: `Bearer ${test1.token}` },
}
);
setCountData(fetchData.data[0]);
} catch (err) {}
};
fetchCount();
}, [post.id, test1.token]);
console.log(countData);
```
console log return : "{COUNT(*): 4}" how can i get (4)
given your trivial example, the trivial solution would be something like -
fetchData.data[0]['COUNT(*)']
however, you should really have a think about the contract on the API, and enforce a certain return type from your API, and not just simply return the response from the SQL query. i.e. your API could possibly return an object like -
{ count: x }
where its up to your API to transform the result from the SQL query in a way that satisfies the contract, that way your React client is disconnected from your database layer and only cares about your API contract.
That way your client side becomes something like -
fetchData.data.count
which wouldn't break if the query where to be updated in some way etc.

How to get error line using Nestjs avoiding duplicate code

I made a controller on nestjs as below.
#Post()
public async addConfig(#Res() res, #Body() createConfigDto: CreateConfigDto) {
let config = null;
try {
config = await this.configService.create(createConfigDto);
} catch (err) {
return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
status: 500,
message: 'Error: Config not created!',
});
}
if (!config) {
return res.status(HttpStatus.NOT_FOUND).json({
status: 404,
message: 'Not Found',
});
}
return res.status(HttpStatus.OK).json({
message: 'Config has been created successfully',
config,
});
}
And there is a service in other file.
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
do something 1
do something 2
do something 3
return result;
}
If an internal server error occurs among "do somehting 1,2 or 3" when I request to this api, it will gives me response 500.
But I want to know in which line the error happend.
Therefore I made catch line function.
const getStackTrace = () => {
const obj = {};
Error.captureStackTrace(obj, getStackTrace);
return obj.stack;
};
And I wrap the code with this function, like this
public async create(createConfigDto: CreateConfigDto): Promise<IConfig> {
try{
do something 1
}catch(error){
console.log(error)
getTrace()
}
try{
do something 2
}catch(error){
console.log(error)
getTrace()
}
try{
do something 3
}catch(error){
console.log(error)
getTrace()
}
return result;
}
But the problem is the service code will grow a lot with this trace function.
I want to know whether there is more efficient way avoiding duplicate code using nestJs for this case.
I think interceptor or execption filter help this.
But I don't know how to code for this case , since I 'm about to start using nestjs.
Thank you for reading my question.

Wait for AWS SNS publish callback to return a value to calling method

I am attempting to send a text message when a user requests to reset their password. I would like to wait for the message to be sent to alert the user if it was successful or not. I am currently attempting to do it as follows:
async function sendResetPasswordTextMessage(req, res) {
let result = {};
let phoneNumber = req.body.phoneNumber;
if (phoneNumber === undefined) {
return sendInvalidParametersMessage(res);
}
phoneNumber = phoneNumber.toString();
const userProfile = await models.UserProfile.findOne({
where: {
phoneNumber: phoneNumber
}
});
************************** RELEVANT CODE TO ISSUE *************************
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
const sent = await AWSSNSClient.sendMessage(message, phoneNumber);
if (!sent) {
result.error = setTitleAndMessage("Error", "An error occurred");
} else {
result.success = setTitleAndMessage("Success", "Message sent");
}
}
return res.send(result);
***************************************************************************
}
In my other class AWSSNSClient, I have the following sendMessage function:
function sendMessage(message, phoneNumber) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
let sent = false;
sns.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
sent = true;
}
});
return sent;
}
I cannot figure out how to make sendMessage wait for sns.publish to return before it returns itself. I have tried making it an async method and adding await on sns.publish, but the function still returns before sent gets set to true.
I know that the messages are sending without error because I am receiving them and no console logs are printed.
Stumbled on this one via Google trying to figure this out myself today - short answer that I am now using:
You can now do this with Async/Await — and Call the AWS service (SNS for example) with a .promise() extension to tell aws-sdk to use the promise-ified version of that service function (SNS) instead of the call back based version.
The only caveat here is the containing function must ALSO be async to utilize the await syntax.
For example:
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("SNS Push Failed:");
console.log(err.stack);
return;
}
console.log('SNS push suceeded: ' + data);
return data;
}).promise();
The important part is the .promise() on the end there. Full docs on using aws-sdk in an async / promise based manner can be found here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html
In order to run another aws-sdk task you would similarly add await and the .promise() extension to that function (assuming that is available).
For anyone who runs into this thread and is actually looking to simply push multiple aws-sdk promises to an array and wait for that WHOLE array to finish (without regard to which promise executes first) I ended up with something like this:
let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return;
}
console.log('Search push suceeded: ' + data);
return data;
}).promise();
snsPromises.push(snsResult)
await Promise.all(snsPromises)
Hope that helps someone that randomly stumbles on this via google like I did!
stackdave will that actually wait?
Necevil "Search push suceeded will get logged twice" because you're mixing calling operations by passing a callback and using promises. You should only use one method of getting the result
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn}).promise()
will do the trick
You can simply use callbacks for that. Modify your sendMessge like this
function sendMessage(message, phoneNumber, cb) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
sns.publish(params, cb);
}
then on your main file you can supply callback like this
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
if (err) {
result.error = setTitleAndMessage("Error", "An error occurred");
}
else {
result.success = setTitleAndMessage("Success", "Message sent");
}
res.send(result);
});
}
Here the right updated API, August 2018, Necevil answer send the sms twice.
// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
accessKeyId: process.env.AMAZON_SMS_ID,
secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});
// parameters
let params = {
Message: contentSMS, // here your sms
PhoneNumber: mobile, // here the cellphone
};
const snsResult = await sns.publish(params, async (err, data) => {
if (err) {
console.log("ERROR", err.stack);
}
console.log('SNS ok: ' , JSON.stringify (data));
});
If you're having issues with duplicate SNS messages being sent, I fixed this issue by utilizing examples from AWS:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
By utilizing a traditional .then() I was able to squash the duplicate message bug mentioned in comments above.
You can create a async function what use the promise method
async function sendMessage(message, phoneNumber){
const params = {
Message: message,
PhoneNumber: phoneNumber
};
return new Promise((resolve, reject) => {
SNS.publish(params, (err, data) => {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return reject(err);
} else {
console.log('Search push suceeded:' + phoneNumber);
return resolve(data);
}
})
});
}
and then you can call
var s= await sendMessage(message,phoneNumber);

Categories

Resources