Returning boolean from mongoose .exists function - javascript

I'm trying to learn some node.js and mongoDB. I'm writing a demo login system to that end.
I have a function called by my main api to check in the mongoDB whether a refreshToken exists.
const checkRefreshTokenDB = (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
RefreshToken.exists(
{ tokenId: decoded.refresh.tokenId },
function (err, result) {
if (err) {
console.log(err);
} else {
console.log('Result: ' + result);
}
}
);
};
I can see the RefreshToken.exists is working find in the console.log. What I'm struggling with is making this function return a simple true/false to the caller. At the moment it seems to be returning a promise.
Any help would be very appreciated
Thanks

One way to resolve the issue is by using async/await.
const checkRefreshTokenDB = async (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
return await RefreshToken.exists({ tokenId: decoded.refresh.tokenId });
};
Now you can call this function as shown below from an async function (await is only valid in async function)
const status = await checkRefreshTokenDB(tokenPayload);
console.log(status)

If it really is returning a promise, then use async/await:
const checkRefreshTokenDB = (tokenPayload) => {
const decoded = jwt.decode(tokenPayload);
RefreshToken.exists(
{ tokenId: decoded.refresh.tokenId }
, async function (err, result) { console.log(await result); });
};

Related

Null return value from a nested async function

How does this function returns null? is it because of the variable scope or execution time of the functions?
async function getBook() {
var book;
await libray.findONe({ cat: 1 }, {}, async (err, res) => {
await section.findONe({ secId: res.secI }, {}, (error, result) => {
book = result;
});
});
book = result;
}
return book;
}
Try this
async function getBook() {
const res = await libray.findOne({ cat: 1 });
const book = await section.findOne({ secId: res.secI });
return book;
}
I think the problem is that you are returning from the function before the async function finishes.
so one convenient way to solve this is to make a callback function from the async function.
Sorry I am not a js guy so I can't actually post code but I think you got the idea..

Cannot resolve Promise in Node.js App with chrome-cookies-secure module

I'm working on a local Node.js app that needs to access the Google Chrome cookies. I've found the chrome-cookies-secure library that seems to do the job but I just can't figure out what's wrong with the code below.
const chrome = require('chrome-cookies-secure');
const domains = [
"google.com"
];
const resolveCookies = async () => {
let result = [];
for(domain of domains) {
await chrome.getCookies(`https://${domain}/`, (err, cookies) => {
result.push(cookies);
// console.log(cookies); //? This is going to correctly print the results
})
}
return result;
}
const final = resolveCookies();
console.log(final); //! This is going to return a Promise { <pending> } object
The idea is that I just want to store the cookies from all the domains in a list but no matter what I cannot resolve the Promise.
I didn't see any examples with the async call for this module but if I don't use it it's going to return me an empty list after the script execution.
My Node Version: v14.4.0
What am I doing wrong?
It looks like the implementation of getCookies is not correctly awaiting the asynchronous processes. You can see in the implementation that although getCookies itself is async, it calls getDerivedKey without awaiting it (and that function isn't async anyway).
Rather than trying to rely on this implementation, I'd suggest using Util.promisify to create a proper promise via the callback:
const util = require('util');
const chrome = require('chrome-cookies-secure');
const getCookies = util.promisify(chrome.getCookies);
// ...
const cookies = await getCookies(`https://${domain}/`);
Note that, as Reece Daniels pointed out in the comments, the getCookies implementation actually takes a profile parameter after the callback; if you need to use that parameter, you can't use the built-in promisify. You'd have to wrap it yourself instead, this could look like e.g.:
const getCookies = (url, format, profile) => new Promise((resolve, reject) => {
chrome.getCookies(url, format, (err, cookies) => {
if (err) {
reject(err);
} else {
resolve(cookies);
}
}, profile);
});
They already tried to fix the promise upstream, but the PR hasn't been merged in nearly nine months.
Note that once you have a working function to call you can also convert:
const resolveCookies = async () => {
let result = [];
for(domain of domains) {
await chrome.getCookies(`https://${domain}/`, (err, cookies) => {
result.push(cookies);
// console.log(cookies); //? This is going to correctly print the results
})
}
return result;
}
to simply:
const resolveCookies = () => Promise.all(domains.map((domain) => getCookies(`https://${domain}/`)));
An async function returns a Promise.
So your resolveCookies function will also return a Promise as you noticed.
You need to either chain the console.log with a .then e.g.
resolveCookies().then(console.log);
Or if you need to set it to a variable like final you need to await that Promise too. In that case you need an async IIFE:
(async () => {
const final = await resolveCookies();
console.log(final);
})();
try this.
const chrome = require('chrome-cookies-secure');
const domains = [
"www.google.com"
];
const resolveCookies = async() => {
let result = [];
for (domain of domains) {
const cookies = await getCookies(domain)
result.push(cookies)
}
return Promise.resolve(result);
}
const getCookies = async (domain) => {
chrome.getCookies(`https://${domain}/`, (err, cookies) => {
return Promise.resolve(cookies);
})
}
resolveCookies().then((resp) => {
console.log('FINAL ',resp)
}).catch((e) => {
console.log('ERROR ', e)
})

Unable to return a value from an async function using firestore

I am new to async and am trying to return a value from a Firestore db using node.
The code does not produce any errors, nor does it produce any results!
I want to read the db, get the first match and return this to the var country.
const {Firestore} = require('#google-cloud/firestore');
const db = new Firestore();
async function getCountry() {
let collectionRef = db.collection('groups');
collectionRef.where('name', '==', 'Australia').get()
.then(snapshot => {
if (snapshot.empty) {
console.log('No matching documents.');
return "Hello World";
}
const docRef = snapshot.docs[0];
return docRef;
})
.catch(err => {
console.log('Error getting documents', err);
});
}
let country = getCountry();
When you declare an function async, that means it always returns a promise. It's generally expected that the code inside it will use await to deal with other promises generated within that function. The final returned promise will resolve with the value returned by the function.
First of all, your async function should look more like this:
async function getCountry() {
let collectionRef = db.collection('groups');
const snapshot = await collectionRef.where('name', '==', 'Australia').get()
if (snapshot.empty) {
console.log('No matching documents.');
// you might want to reconsider this value
return "Hello World";
}
else {
return snapshot.docs[0];
})
}
Since it returns a promise, you would invoke it like any other function that returns a promise:
try {
let country = await getCountry();
}
catch (error) {
console.error(...)
}
If you can't use await in the context of your call to getCountry(), you will have to handle it normally:
getCountry()
.then(country => {
console.log(country);
})
.catch(error => {
console.error(...)
})
The moment you sign up to use async/await instead of then/catch, things become much different. I suggest reading up more on how it works.

Async Wait Issue with Service when called out from the Controller in Nodejs

I am currently trying to do a get request in my NodeJS API, get some data and return the modified value.
From what I read in other similar questions is that you cannot just return the modified object but you need to use a callback function or a promise in order to return it. I have a standard MVC pattern where I use a controller, service.
Here is my service:
const rp = require('request-promise');
exports.RequestUserPermissions = async function(role, next) {
try {
await rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
});
} catch (error) {
console.log(error);
next(error);
}
};
Here is my controller:
const UserPermissionsService = require('../services/userPermissions.service');
exports.getUserPermissions = async function(req, res) {
try {
const role = req.headers.role; // console.log(req.headers.role);
const loggedInUserPermissions = await UserPermissionsService.RequestUserPermissions(role);
return res.status(200).json({ status: 200, data: loggedInUserPermissions, message: 'User permissions retrieved.' });
} catch (error) {
throw Error(error, 'error inside the get.user.permissions function');
}
};
So my issue is that I'm trying to return the value of filteredPermissions to my controller but I keep getting undefined. Which I guess it's a async - await issue. Meaning that the function ends before I make my calculations.
I originally had my service as:
await request.get('https://api.myjson.com/bins/7jau8', (error, response, body) => {
if (!error && response.statusCode === 200) {
const permissionsResponse = JSON.parse(body);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
return permissionsResponse;
} else {
console.log('Got an error:', error);
}
});
but I changed it to use the request-promise module, so that I can return my response. What am I doing wrong ? How can I pass my calculations properly??
Change this:
await rp('https://api.myjson.com/bins/7jau8')
to this:
return rp('https://api.myjson.com/bins/7jau8')
You need to be returning something useful from your exports.RequestUserPermissions function. As it stands now, there's no return value from that function which means the promise it returns will just have an undefined resolved value which is apparently what you are experiencing.
Then, I'd suggest using a .catch() for the error condition. And, you need to allow the caller to see the error (probably as a rejected promise) so it can know when there's an error.
I would suggest this:
const rp = require('request-promise');
exports.RequestUserPermissions = function(role, next) {
return rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
}).catch(error => {
console.log(error);
next(error);
throw error;
});
};
The spec for exactly what you want is a bit confused. To be able to test things with the URL you gave me, I created a simple stand-alone node program here. This looks for one matching role and returns that. If no matching role is found, it resolves to null. You could also make that reject, depending upon how the caller wants no matching role to work.
const rp = require('request-promise');
function getRole(role) {
return rp({uri: "https://api.myjson.com/bins/7jau8", json: true}).then(data => {
// need to find the matching role
// apparently role can be a string or an array of strings
for (let item of data) {
if (item[role]) {
return item[role];
}
}
return null;
});
}
getRole("admin").then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
When, I run this, I get this output:
{ static:
[ 'posts:list',
'posts:create',
'posts:edit',
'posts:delete',
'users:get',
'users:getSelf',
'home-page:visit',
'dashboard-page:visit' ]
}
Hopefully, can you take this an modify to fit your other needs.
Note: I'm using the json:true option with rp() so it will parse the JSON response for me automatically.
If you are using async/await with request-promise then you don't need to call .then(), you can just assign your rp call directly to a variable. For example this:
await rp('https://api.myjson.com/bins/7jau8').then(response => {
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;
});
Would become this:
const response = await rp('https://api.myjson.com/bins/7jau8');
const permissionsResponse = JSON.parse(response);
const filteredPermissions = permissionsResponse.find(function(x) {
return Object.keys(x).indexOf(role) > -1;
});
console.log(filteredPermissions); // I GET UNDEFINED HERE.
return filteredPermissions;

NodeJS Express app await is only valid in async function but this clearly is async function?

I have made a function to check if a certain thing already exists in the database. I have simply copy-pasted the logic I'm using to get something in the database and changed the query object + what is returned. But now it seems that node doesn't like that and just throws an error that makes no sense to me.
Where I call the function:
let exists = await queryDatabaseExists(uniqueQuery, res);
The function that I'm calling:
async function queryDatabaseExists(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.recordset.rowsAffected[0] = 1){return true} else { return false }
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
The error that I'm getting:
let exists = await queryDatabaseExists(uniqueQuery, res);
^^^^^
SyntaxError: await is only valid in async function
ALL code for that route:
router.post("/admin/category", (req, res) => {
uniqueQuery = `SELECT [name] from [dbo].[idtTV_categories] WHERE [name] = '${req.body.name}'`
getQuery = `SELECT [id]
,[name]
,[description]
,[created_time]
,[created_by] from [dbo].[idtTV_categories]`
standardQuery = `INSERT INTO [dbo].[idtTV_categories] ([name],[description],[created_time],[created_by])
VALUES
('${req.body.name}',
'${req.body.description}',
SYSDATETIME(),
'${req.user.name}')`;
let exists = checkIfExists();
function checkIfExists() { result = await queryDatabaseExists(uniqueQuery, res); return result} ;
console.log(exists);
if(req.user.roles.some(role => role === admin || role === editor)){
if(!existsInDatabase){
if(queryDatabase(standardQuery, res)){queryDatabase_get(getQuery, res)}
}
}
else { res.statusMessage = `${req.user.name} is not authorized to add categories.`;
console.log(req.user.roles)
res.status(520).send() };
})
All functions being called:
///////////// MAIN QUERYING FUNCTION //////////////////////
async function queryDatabase_get(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
res.send(result.recordset);
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
async function queryDatabaseExists(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.recordset.rowsAffected[0] = 1){return true} else { return false }
} catch (err) {
res.status(520).send();
}
}
async function queryDatabase(queryParam, res) {
try {
const cp = new sql.ConnectionPool(config);
await cp.connect();
let result = await cp.request().query(queryParam);
if(result.rowsAffected > 0){ return true }
} catch (err) {
res.status(520).send(`Database error: ${err}`);
}
}
it must be inside async.
ex:
app.post('/', async (req, res) => {
let exists = await queryDatabaseExists(uniqueQuery, res);
});
This means that the function in which the call to queryDatabaseExists is performed must also be async, in order to use the await keyword inside it. The queryDatabaseExists function itself looks correct.
queryDatabaseExists function need to return promise if not you cannot use await
await command expect a promise to be return by the function link
let exists = await queryDatabaseExists(uniqueQuery, res);
await can only be used in async function. For your scenario you wanted wait for result from uniquequery. First you have to make change in your router.post callback like router.post('/url',async(req,res)=>{}); for making a synchornus call to checkifexist function. Second in order to use await in checkifexist function you have to make changes to checkisexist function to async function checkifexist(){}. Thirdly you wanted to wait for DB response for that you have use await while calling checkifexist function --> let result=await checkifexist(). you can check MDN website for better understanding.
router.post('url',async(req,res)=>{// in order to use await in checkifexist
//your rest of the code.
let result=await checkifexist();// waiting for db result
async function checkifexist(){//your awaited code.}
console.log(result);
});

Categories