I'm trying to export a variable in node.js like this:
let news = [];
const fetchNews = new Promise ((resolve, reject) => {
let query = 'SELECT id, name FROM news';
mysql.query(query, [], (error, results) => {
if (error)
reject({error: `DB Error: ${error.code} (${error.sqlState})`})
results = JSON.parse(JSON.stringify(results));
news = results;
resolve(results);
});
});
if(!news.length)
fetchNews
.then(results => {news = results})
.catch(err => {console.log('Unable to fetch news', err)});
exports.news = news;
When I use this code in some other module like this:
const news = require('./news.js').news;
console.log(news);
//returns [];
Can somebody point out my mistake in first code?
There are a couple of things that seem odd in the way you are doing this:
You have an async operation but you want just the value without actually awaiting on the operation to complete. Try something like this:
module.exports = new Promise ((resolve, reject) => {
mysql.query('SELECT id, name FROM news', (error, results) => {
if (error)
reject({error: `DB Error: ${error.code} (${error.sqlState})`})
resolve(JSON.parse(JSON.stringify(results)));
});
});
Then to get the news:
var getNewsAsync = require('./news')
getNewsAsync.then(news => console.log(news))
It would be cleaner/shorter if you actually utilize async/await with the mysql lib.
Update:
With Node 8 and above you should be able to promisify the mySQL lib methods. Although there might be better npm options out there to get this to work. Here is an untested version:
const mysql = require('mysql');
const util = require('util');
const conn = mysql.createConnection({yourHOST/USER/PW/DB});
const query = util.promisify(conn.query).bind(conn);
module.exports = async () => {
try {return await query('SELECT id, name FROM news')} finally {conn.end()}
}
To get the news:
var getNewsAsync = require('./news')
console.log(await getNewsAsync())
Related
I need to filter a firestore data by string, and knowing that firestore don't have a proper way to do this inside his tools (Something as "%LIKE%" SQL operator) our new strategy is to use cloud functions to filter this data using a regex and recover it after.
But we having some troubles:
1-Can we manage assync functions inside Cloud Functions?
2-After this function, how can we recover this data? (We trying to use Fetch(),but looks like it don't works.)
Here's my Cloud Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(MY CREDENTIALS)
exports.filterAdverts = functions.https.onRequest( (req, res) => {
let vm = this;
let filteredResults = [];
let {filter,id_client} = JSON.parse(req.body);
let regex = new RegExp(filtro, 'i');
admin
.firestore()
.collection('database')
.doc(id_client)
.collection('classifieds')
.where('active', '==', 1)
.get().then(snapshot => {
snapshot.docs.forEach(doc => {
if (doc.data().txt_comentary.match(regex)) {
filteredResults.push(doc.data())
}
})
});
res.send(filteredResults.toString())
});
As you can see, i need to filter the variable txt_comentary by the Regex. Here's the fetch function:
filterAds: function(){
let filter = {filter:this.form_seach.filtro_comentary, id_cliente:this.id_cliente};
fetch('Cloud-function-URL', {
headers: {'Content-Type':'application/x-www-form-urlencoded'},
method: 'GET',
mode: 'no-cors'
}).then(async (response) => {
await console.log(response)
}).catch(error => {
console.log(error)
})
I'm really stucked to do this, can anybody help me?
I reach a result, i'm used the onCall function to trigger it. Here's the code from cloud function:
exports.filterAds = functions.https.onCall( async (data, context) => {
let vm = this;
let filteredResults = [];
let {filter,id_client} = data;
let regex = new RegExp(filter, 'i');
await admin.firestore().collection('database').doc(id_client).collection('classifieds').where('active', '==', 1) .get().then(snapshot => {
snapshot.docs.forEach(doc => {
if (doc.data().txt_comentary.match(regex)) {
filteredResults.push(doc.data())
}
})
})
return filteredResults;
});
and here's the function to trigger it:
filter_Ads: function () {
const vm = this;
const filteredValues = firebase.functions().httpsCallable("filtrarAnuncios");
valoresFiltrados({
filter: *input string*,
id_cliente: *part of path in my firebase search*,
})
.then(async (response) => {
console.log(respose)
})
.catch((error) => {
console.log(error);
});
},
With this i can filter by the regex and recover the result from this cloud function.
Yes you can specify the version of nodejs and use a modern one that handle async / await.
you should call res.send inside your .then(snapshot => {...}) not after, because here you are calling it before getting the data from the database
Also in your test, instead of await console.log(response) you should do console.log(await response.text())
A few other things are surprising with your code, like how you just .toString your array instead of sending it as JSON
I'm trying to get the hang of using Mongoose promises with the async/await functionality of Node.js.
However I have problems with the second "find" function because is linked to the first one, i think because i dont have the first find result.
How can I wait for the response of the first function and then execute the second?
exports.permissions_Check2 = async function(params){
const Sessioni = require('../models/Sessioni');
const Permessi = require('../models/Permessi');
const express = require ('express');
var token= params['Token'];
var tabelle = params['Tabelle'];
var DataSession= [];
var out;
try{
const sessioni = await Sessioni.findOne({token: token}).exec();
const permessi = await Permessi.findOne({IDGruppo: sessioni.IDGruppo}).exec();
out={
IDAccesso: sessioni._id,
IDUser: sessioni.IDUser,
IDGruppo:sessioni.IDGruppo,
Permessi: permessi
}
return out;
} catch (err){
return err;
}
return out;
}
output:
{
IDAccesso: "ehwuhf7867tgyb",
IDUser: 1,
IDGruppo: 1,
Permessi: null }
What about using Promises?
That will look like
Sessioni.findOne({token: token})
.exec()
.then(sessioni => {
Permessi.findOne({IDGruppo: sessioni.IDGruppo})
.exec()
.then(permessi => {
out={
IDAccesso: sessioni._id,
IDUser: sessioni.IDUser,
IDGruppo:sessioni.IDGruppo,
Permessi: permessi
}
}).catch(e => throw e);
}).catch(e => throw e)
I'm not sure what DB you're using, but hope that will help
I have created a promise, which would take an array of firebase keys as input, loop them to query firebase realtime database. My issue is even after I use async await, for firebase to provide results back, promise is getting resolved quickly.
function firebaseQuery(keys){
const result = [];
return new Promise((resolve, reject) => {
keys.forEach((key) => {
const snap = app.child(key).once('value');
const snapJSON = await snap.then(snapshot => snapshot.toJSON());
result.push({ key: key, post: snapJSON });
console.log(result);
});
resolve(result);
});
}
forEach does not pause for await statements, so it won't work like this (https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404). Better to map the keys into an array of promises, and then use Promise.all() to wait until they all resolve. Something like this (just make sure to handle your errors)
async function firebaseQuery(keys){
const result = await Promise.all(keys.map(async key => {
const snap = app.child(key).once('value');
const snapJSON = await snap.then(snapshot => snapshot.toJSON());
const returnValue = { key: key, post: snapJSON };
console.log(returnValue);
return returnValue;
}));
}
Simple call to ec2 Describing Security groups and returning the security group ID. Using Async / await, but when logging the return value, I get undefined. I fully admit I'm coming from Python and I've tried my hardest to wrap my brain around async calls. I thought I had it nailed, but I'm obviously missing something.
'use strict';
// Load Modules
const AWS = require('aws-sdk')
//Set the region
AWS.config.update({region: 'us-west-2'});
// Call AWS Resources
const ec2 = new AWS.EC2();
// Get Security Group ID From Event
const getSgIdFromEvent = async (event) => {
var ec2params = { Filters: [{Name: 'tag:t_whitelist',Values[event['site']]}]};
await ec2.describeSecurityGroups(ec2params, function (err, response) {
if (err) {return console.error(err.message)}
else {
var sgId = response.SecurityGroups[0].GroupId;
return sgId;
};
});
};
// MAIN FUNCTION
exports.handler = (event, context) => {
getSgIdFromEvent(event)
.then(sgId => {console.log(sgId)});
}
"sgId" should return the security group ID. It does print out fine in the original function before the return.
Typically if it is an async call you want you handle it similar to this way without using a callback
// Load Modules
const AWS = require('aws-sdk')
//Set the region
AWS.config.update({ region: 'us-west-2' });
// Call AWS Resources
const ec2 = new AWS.EC2();
// Get Security Group ID From Event
const getSgIdFromEvent = async (event) => {
var ec2params = { Filters: [{ Name: 'tag:t_whitelist', Values[event['site']]}] };
try {
const securityGroupsDesc = await ec2.describeSecurityGroups(ec2params).promise();
const sgId = securityGroupsDesc.SecurityGroups[0].GroupId;
//do something with the returned result
return sgId;
}
catch (error) {
console.log('handle error');
// throw error;
}
});
};
// MAIN FUNCTION
exports.handler = (event, context) => {
getSgIdFromEvent(event)
.then(sgId => { console.log(sgId) });
}
however if it doesn't support async you just use the callback to handle the returned data or error without using async function.However Reading into AWS docs you can find that the function ec2.describeSecurityGroups() returns an AWS Request
which has a method promise() that needs to be invoked to send the request and get a promise returned.Note that the try catch here is not needed but good to have in case error occurs during the process.
As I said in the comment, chance are that describeSecurityGroups doesn't return a Promise. Try transforming it explictly in a Promise instead:
const promiseResponse = await new Promise((res, rej) => {
ec2.describeSecurityGroups(ec2params, function (err, response) {
if (err) {return rej(err.message)}
else {
var sgId = response.SecurityGroups[0].GroupId;
res(sgId);
};
})
});
// promiseResponse is now equal to sgId inside the callback
return promiseResponse; // this will work because the function is async
Note: You can drop the else keyword
Here is the code that worked using async / await. Thanks to #Cristian Traina I realized ec2.describeSecurityGroups wasn't returning a promise, it was returning an AWS.Event.
// Get Security Group ID From Event
const getSgIdFromEvent = async (event) => {
console.log('Getting Security Group ID')
var params = { Filters: [{Name: 'tag:t_whitelist', Values
[event['site']]}]};
const describeSG = await ec2.describeSecurityGroups(params).promise();
return describeSG.SecurityGroups[0].GroupId;
};
// Get Ingress Rules from Security Group
const getSgIngressRules = async (sgId) => {
console.log(`Getting SG Ingress rules for ${sgId}`)
var params = { GroupIds: [ sgId]};
try{
const ingressRules = await ec2.describeSecurityGroups(params).promise();
return ingressRules;
}
catch (error) {
console.log("Something went wrong getting Ingress Ruls");
}
};
// MAIN FUNCTION
exports.handler = (event, context) => {
getSgIdFromEvent(event)
.then(sgId => {return getSgIngressRules(sgId);})
.then(ingressRules => {console.log(ingressRules);});
}
I submitted this as the answer now since the getSgIdFromEvent function I have, is only 8 lines and still using the async/await like I was desiring.
What I was missing was the .promise() on the end of the function and returning that promise.
Thanks for all the responses!
I am promisifying multiparty to use its form.parse. It works fine but form.parse does not return a promise whose then/catch value I can use.
var Promise = require('bluebird');
var multiparty = Promise.promisifyAll(require('multiparty'), {multiArgs:true})
var form = new multiparty.Form();
form.parse({}).then((data)=>{console.log(data)});
Here is my solution using build-in Promise:
const promisifyUpload = (req) => new Promise((resolve, reject) => {
const form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
if (err) return reject(err);
return resolve([fields, files]);
});
});
And usage:
const [fields, files] = await promisifyUpload(req)
My solution for waiting until all the parts are read:
const multipartParser = new Form();
multipartParser.on('error', error => { /* do something sensible */ });
const partLatches: Latch<void, Error>[] = [];
multipartParser.on('part', async part => {
// Latch must be created and pushed *before* any async/await activity!
const partLatch = createLatch();
partLatches.push(partLatch);
const bodyPart = await readPart(part);
// do something with the body part
partLatch.resolve();
});
const bodyLatch = createLatch();
multipartParser.on('close', () => {
logger.debug('Done parsing whole body');
bodyLatch.resolve();
});
multipartParser.parse(req);
await bodyLatch;
await Promise.all(partLatches.map(latch => latch.promise));
This can be handy in cases where you want to process the parts further, for example parse and validate them, perhaps store them in a database.