I have 13.000 documents from MongoDB where I have address line + Postcode, im trying to make a request for each of them to Google's geocoding API and get LAT + LONG for them so I can have them appear dynamically on a map search.
I have designed the following for of loop and I'm testing with 10 items at a time but due to the async nature of both the writing to DB call and calling the API, the LAT/LONG coordinates from the HTTPS requests ends up being undefined/unavailable to knex's INSERT and the loop seems to keep going on and on...
Is it possible to write this in a blocking way? So the for loop doesn't go to the next item unless both promises have been resolved?
The code:
let results = [];
await forLoop();
async function forLoop() {
for (job of allJobs) {
const geoData = await getGeoData(
job.site.addressLine1,
job.site.postcode
);
const dbResult = await addToDb(geoData);
results.push(dbResult);
async function getGeoData(addressLine1, postcode) {
const friendlyAddress = encodeURIComponent(addressLine1 + ' ' + postcode);
https
.get(
'https://maps.googleapis.com/maps/api/geocode/json?key=<API_KEY_IGNORE_THIS_ITS_HARDCODED_IN_MY_REAL_CODE>&address=' +
friendlyAddress,
resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
console.log(JSON.parse(data).explanation);
let result = JSON.parse(data);
return result;
});
}
)
.on('error', err => {
console.log('Error: ' + err.message);
});
}
async function addToDb(geoData) {
try {
await knex('LOCATIONS')
.returning('*')
.insert({
UPRN: job.site.UPRN,
lat: geoData.results[0].geometry.location.lat,
lng: geoData.results[0].geometry.location.lng
});
} catch (err) {
err.name = 'database';
next(err);
}
}
}
}
res.send(results);
I've made sure the codebase has no nulls and have tested both the api call and the database call to make sure they work in isolation.