I was trying to solve it using inHTMLData() of xss-filters library like this answer. But it did not work as req.query is an object
function data(req, res) {
fetchData(req.params.uniqueId, req.params.name, req.query) // query has multiple data
.then((result) => {res.json(result)})
.catch((error) => res.json(error));
};
Using xss-filters npm library
First stringify query string
Use inHTMLData of xss-filters
Use JSON.parse
const xssFilters = require('xss-filters');
function data(req, res) {
const uniqueId = xssFilters.inHTMLData(req.params.uniqueId);
const name = xssFilters.inHTMLData(req.params.name);
const query = xssFilters.inHTMLData(JSON.stringify(req.query));
fetchData(uniqueId, name, JSON.parse(query)) // query has multiple data
.then((result) => {res.json(result)})
.catch((error) => res.json(error));
};
Related
Multiple fetch res render function , hey I am trying to perform and multiple res render function in ejs but my data is lost is their any fix
app.get("/" , function(req,res){
fetch(`${domain}/popular`)
.then(res => res.text())
.then(datap => {
res.render('home',{datap : JSON.parse(datap)});})
fetch(`${domain}/recent-release`)
.then(res => res.text())
.then(datar => {
res.render('home',{datar : JSON.parse(datar)});})
})
i want to make multiple fetch function but the datar is replacing datap
Convert the function to async, await for the two requests, render only when they're done. (I also took the liberty of using the asynchronous res.json() parser instead of res.text() + JSON.parse.)
app.get("/", async function(req, res) {
const res1 = await fetch(`${domain}/popular`);
const datap = await res1.json();
const res2 = await fetch(`${domain}/recent-release`);
const datar = await res2.json();
res.render("home", { datap, datar });
});
(A future optimization could be to do the two requests in parallel using Promise.all().)
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 construct an array of database responses using the async await syntax.
I understand that since async await is just a way of wrapping promises in nicer syntax, it should be easy to convert the promise-oriented instructions given here into that format.
Here's what I have:
const sqlite3 = require('sqlite3').verbose();
const express = require('express')
const bodyParser = require("body-parser")
async function getDB(dbname) {
let db = new sqlite3.Database(dbname)
return db;
}
app.get('/', async (req,res) => {
let db = await getDB(dbname)
let r = await db.serialize(() => {
let results = []
db.each(`SELECT * FROM MyTable LIMIT 3`, (err, row) => {
if (err) {
console.error(err.message);
}
let m = row.id;
console.log(m);
results.push(m)
});
return results
});
res.send(await r)
})
app.listen(port, ipaddr);
When I call this, the response is:
{"open":false,"filename":"dbname.db","mode":65542}
but I expect:
[1,2,3]
What's happening and how do I fix it?
In the console, I can see the records are being retrieved:
[
1,
2,
3
] # this is exactly the thing I want returned! Why can't I retrieve it?
So I know the database call actually works, but I can't seem to get them /into/ any object I can get out of the await.
Try the sqlite package, rather than the sqlite3 used in the demo. It has better support for async await.
I've been using firebase functions test to do some testing on my functions. I have some code that is supposed to post a thing to firestore, basically in the same way that the examples show to do in the realtime database examples:
exports.addMessage = functions.https.onRequest((req, res) => {
const original = req.query.text;
admin.firestore()
.collection('messages')
.add({ original })
.then(documentReference => res.send(documentReference))
.catch(error => res.send(error));
});
For my test, I've spoofed some basic functionality using sinon, mocha and chai. Here is my current test, which is failing with the error message: TypeError: firestoreService.snapshot_ is not a function
describe('addMessage', () => {
// add message should add a message to the database
let oldDatabase;
before(() => {
// Save the old database method so it can be restored after the test.
oldDatabase = admin.firestore;
});
after(() => {
// Restoring admin.database() to the original method.
admin.firestore = oldDatabase;
});
it('should return the correct data', (done) => {
// create stubs
const refStub = sinon.stub();
// create a fake request object
const req = {
query : {
text: 'fly you fools!'
}
};
const snap = test.firestore.makeDocumentSnapshot({ original: req.query.text }, 'messages/1234');
// create a fake document reference
const fakeDocRef = snap._ref;
// create a fake response object
const res = {
send: returnedDocRef => {
// test the result
assert.equal(returnedDocRef, fakeDocRef);
done();
}
};
// spoof firestore
const adminStub = sinon.stub(admin, 'firestore').get(() => () => {
return {
collection: () => {
return {
add: (data) => {
const secondSnap = test.firestore.makeDocumentSnapshot(data, 'messages/1234');
const anotherFakeDocRef = secondSnap._ref;
return Promise.resolve(anotherFakeDocRef);
}
}
}
}
});
// call the function to execute the test above
myFunctions.addMessage(req, res);
});
});
My question is how the heck do I fix this?
I previously had a test that was just passing the first snap and fakeDocRef, and my test was passing fine, but as soon as I resolve the promise with the new fake document reference, it fails...
Any help would be appreciated! Thanks!
There are three different types of the calls, that are different:
Operating on the Collections.
Operating on the Documents.
Operating on the results of the query.
They have to be used consistently.
Please refer a documentation to see the difference operation on the collection and the document.
I am working on an async problem. I'm making a web scraper and after I scrape the web, I need to put the data in my MongoDB database after putting it in. I need to send it into the frontend, but since I have a loop the elements I can't put the res.json() inside, as it'll gave an error (you can only send once after res.json()).
I'm stuck here. I've used promises before, but this is confusing.
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
articles
.create(data)
.then((resp) => results.push(resp))
// .then((resp) => Promise.resolve(results)) //
// .then((jsonDta ) => res.json(jsonData)) // error you can only give response once.
.catch((err) => reject(err));
});
console.log(results); // empty array
res.json(results)// empty
});
});
My plan is:
to scrape a site (loop the elements)
then save into MongoDB (push the data into an array)
then after the loop pass it to the frontend.
I need to put the query method create... inside the loop because I need each data to have an id.
Instead of trying to accumulate results directly, you can map the elements contained in $('h2.story-heading, p.summary') to an array of promises, then aggregate with Promise.all(). The results you want will be delivered by Promise.all(...).then(...).
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
const promises = $('h2.story-heading, p.summary')
.get() // as in jQuery, .get() unwraps Cheerio and returns Array
.map(function(element) { // this is Array.prototype.map()
return articles.create({
'title': $(element).children().text(),
'link': $(element).children().attr('href'),
'summary': $(element).children().text()
})
.catch(err => { // catch so any one failure doesn't scupper the whole scrape.
return {}; // on failure of articles.create(), inject some kind of default object (or string or whatever).
});
});
// At this point, you have an array of promises, which need to be aggregated with Promise.all().
Promise.all(promises)
.then(results => { // Promise.all() should accept whatever promises are returned by articles.create().
console.log(results);
res.json(results);
});
});
});
If you want any single failure to scupper the whole scrape, then omit the catch() and add catch() to the Promise.all().then() chain.
Notes:
For .get() (and most other methods), the jQuery documentation is better than the Cheerio documentation (but be careful because Cheerio is a lean version of jQuery).
At no point do you need new Promise(). All the promises you need are returned by articles.create().
Something like this might work (code not tested)
router.get('/scrape', (req, res) => {
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
// An empty array to save the data that we'll scrape
const results = [];
$('h2.story-heading, p.summary').each(function(i, element) {
const link = $(element)
.children()
.attr('href');
const title = $(element)
.children()
.text();
const summary = $(element)
.children()
.text();
const data = {
title: title,
link: link,
summary: summary,
};
const articleCreate = articles.create(data);
results.push(articleCreate);
});
console.log(results); // this is array of promise functions.
Promise.all(results).then(allResults => {
res.json(allResults)
});
// or you could use array.reduce for sequantial resolve instead of Promise.all
});
});
Use .map function to return all promises to Promise.all and then return the results.
request('http://www.nytimes.com', function test(error, response, html) {
const $ = cheerio.load(html);
var summary = $('h2.story-heading, p.summary')
Promise.all(summary.map((i, element) =>{
const data = {
title: $(element).children().text(),
link: $(element).children().attr('href'),
summary: $(element).children().text(),
};
return articles
.create(data)
}).get())
.then((result)=>{
console.log(result);
res.json(result);
});
})