对于循环进行 HTTPS 地理编码 api 调用并在结果中将坐标输入 SQL 数据库,如何让 Node 的 HTTPS 模块工作?
For of loop to make HTTPS geocoding api call and on result input the coordinates into SQL database, how to get Node's HTTPS module to work?
我有来自 MongoDB 的 13.000 个文档,其中有地址行 + 邮政编码,我正在尝试对每个文档发出请求 Google 的地理编码 API 并获取 LAT + 对他们来说很长,所以我可以让他们动态地出现在地图搜索中。
我设计了以下 for of 循环,我一次测试 10 个项目,但由于写入数据库调用和调用 API 的异步性质,LAT/LONG 来自 HTTPS 请求的坐标最终成为 undefined/unavailable 到 knex 的 INSERT 并且循环似乎一直在继续...
能不能用阻塞的方式写这个?所以除非两个承诺都已解决,否则 for 循环不会转到下一个项目?
代码:
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);
我已确保代码库没有空值,并测试了 api 调用和数据库调用以确保它们独立工作。
只需使用承诺(或回调)
我知道每个人都讨厌 JavaScript,所以这些反惯用转译器和新语言 "features" 的存在是为了让 JavaScript 看起来像 C# 等等,但老实说,它更容易以最初设计的方式使用该语言(否则使用 Go 或其他一些实际上按照您想要的方式运行的语言 - 并且无论如何性能更高)。如果您必须在应用程序中公开 async/await,请将其放在界面上,而不是到处乱扔。
我的 2¢.
我将编写一些伪代码来向您展示这有多么容易:
function doItAll(jobs) {
var results = [];
function next() {
var job = jobs.shift();
if (!job) {
return Promise.resolve(results);
}
return makeRequest(job.url).then(function (stuff) {
return updateDb().then(function (dbStuff) {
results.push(dbStuff);
}).then(next);
});
}
return next();
}
function makeRequest() {
return new Promise(function (resolve, reject) {
var resp = http.get('...', {...});
resp.on('end', function () {
// ... do whatever
resolve();
});
});
}
简单。易于阅读。 1:1 代码的外观与实际发生的事情之间的对应关系。不要试图 "force" JavaScript 表现得与设计方式背道而驰。
你学习理解异步代码的时间越长,理解它的时间就越长。
投入学习写作 JavaScript "the JavaScript way"! :D
这是我更新后的功能,可以正常同步运行,一个一个地获取数据并将其添加到数据库,然后再移动到下一个。
我通过自定义@coolAJ86 的回答做到了这一点,我已将其标记为正确的,但我认为这对绊倒这个线程的人看到我的最终、工作和测试版本会有所帮助。
var geoApiUrl =
'https://maps.googleapis.com/maps/api/geocode/json?key=<<MY API KEY>>&address=';
doItAll(allJobs)
function doItAll(jobs) {
var results = [];
var errors = [];
function nextJob() {
var job = jobs.shift();
if (!job) {
return Promise.resolve(results);
}
var friendlyAddress =
geoApiUrl +
encodeURIComponent(job.addressLine1 + ' ' + job.postcode);
return makeRequest(friendlyAddress).then(function(result) {
if((result.results[0] === undefined) || (result.results[0].geometry === undefined)){
nextJob();
} else {
return knex('LOCATIONS')
.returning('*')
.insert({
UPRN: job.UPRN,
lat: result.results[0].geometry.location.lat,
lng: result.results[0].geometry.location.lng,
title: job.title,
postcode: job.postcode,
addressLine1: job.addressLine1,
theo_id: job.clientId
})
.then(function(data) {
// console.log('KNEX CALLBACK COMING')
// console.log(data[0])
console.log(data[0]);
results.push(data[0]);
nextJob();
})
.catch(function(err) {
console.log(err);
errors.push(job);
});
}
});
}
return nextJob();
}
function makeRequest(url) {
return new Promise(function(resolve, reject) {
https
.get(url, resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
let result = JSON.parse(data);
resolve(result);
});
})
.on('error', err => {
console.log('Error: ' + err.message);
reject(err);
});
});
}
我有来自 MongoDB 的 13.000 个文档,其中有地址行 + 邮政编码,我正在尝试对每个文档发出请求 Google 的地理编码 API 并获取 LAT + 对他们来说很长,所以我可以让他们动态地出现在地图搜索中。
我设计了以下 for of 循环,我一次测试 10 个项目,但由于写入数据库调用和调用 API 的异步性质,LAT/LONG 来自 HTTPS 请求的坐标最终成为 undefined/unavailable 到 knex 的 INSERT 并且循环似乎一直在继续...
能不能用阻塞的方式写这个?所以除非两个承诺都已解决,否则 for 循环不会转到下一个项目?
代码:
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);
我已确保代码库没有空值,并测试了 api 调用和数据库调用以确保它们独立工作。
只需使用承诺(或回调)
我知道每个人都讨厌 JavaScript,所以这些反惯用转译器和新语言 "features" 的存在是为了让 JavaScript 看起来像 C# 等等,但老实说,它更容易以最初设计的方式使用该语言(否则使用 Go 或其他一些实际上按照您想要的方式运行的语言 - 并且无论如何性能更高)。如果您必须在应用程序中公开 async/await,请将其放在界面上,而不是到处乱扔。
我的 2¢.
我将编写一些伪代码来向您展示这有多么容易:
function doItAll(jobs) {
var results = [];
function next() {
var job = jobs.shift();
if (!job) {
return Promise.resolve(results);
}
return makeRequest(job.url).then(function (stuff) {
return updateDb().then(function (dbStuff) {
results.push(dbStuff);
}).then(next);
});
}
return next();
}
function makeRequest() {
return new Promise(function (resolve, reject) {
var resp = http.get('...', {...});
resp.on('end', function () {
// ... do whatever
resolve();
});
});
}
简单。易于阅读。 1:1 代码的外观与实际发生的事情之间的对应关系。不要试图 "force" JavaScript 表现得与设计方式背道而驰。
你学习理解异步代码的时间越长,理解它的时间就越长。
投入学习写作 JavaScript "the JavaScript way"! :D
这是我更新后的功能,可以正常同步运行,一个一个地获取数据并将其添加到数据库,然后再移动到下一个。
我通过自定义@coolAJ86 的回答做到了这一点,我已将其标记为正确的,但我认为这对绊倒这个线程的人看到我的最终、工作和测试版本会有所帮助。
var geoApiUrl =
'https://maps.googleapis.com/maps/api/geocode/json?key=<<MY API KEY>>&address=';
doItAll(allJobs)
function doItAll(jobs) {
var results = [];
var errors = [];
function nextJob() {
var job = jobs.shift();
if (!job) {
return Promise.resolve(results);
}
var friendlyAddress =
geoApiUrl +
encodeURIComponent(job.addressLine1 + ' ' + job.postcode);
return makeRequest(friendlyAddress).then(function(result) {
if((result.results[0] === undefined) || (result.results[0].geometry === undefined)){
nextJob();
} else {
return knex('LOCATIONS')
.returning('*')
.insert({
UPRN: job.UPRN,
lat: result.results[0].geometry.location.lat,
lng: result.results[0].geometry.location.lng,
title: job.title,
postcode: job.postcode,
addressLine1: job.addressLine1,
theo_id: job.clientId
})
.then(function(data) {
// console.log('KNEX CALLBACK COMING')
// console.log(data[0])
console.log(data[0]);
results.push(data[0]);
nextJob();
})
.catch(function(err) {
console.log(err);
errors.push(job);
});
}
});
}
return nextJob();
}
function makeRequest(url) {
return new Promise(function(resolve, reject) {
https
.get(url, resp => {
let data = '';
resp.on('data', chunk => {
data += chunk;
});
// The whole response has been received. Print out the result.
resp.on('end', () => {
let result = JSON.parse(data);
resolve(result);
});
})
.on('error', err => {
console.log('Error: ' + err.message);
reject(err);
});
});
}