首页 > 解决方案 > 异步生成反向地理编码地址列表,无 API 速率限制

问题描述

我正在使用我的 Mongo 数据库(使用 Mongoose)中的节点脚本生成测试/开发虚拟数据,其中包括地理位置坐标。(套lat/lon)。架构如下:

    location: {
      type: {
        type: String,
        enum: ["Point"], // 'location.type' must be 'Point'
        default: "Point",
      },
      coordinates: {
        type: [Number],
        required: true,
      },
      geocoded: {
        type: String, // this has to be done with an external API
      },
    },

出于这个原因,我有一个外部(付费)反向地理编码 API,我想要/需要为每个文档/坐标集调用它。Geocoding API 虽然有一个速率限制器,所以我遇到了429- 请求太多。我正在寻找一种干净简单的解决方案来按顺序运行我的请求,并在每个 HTTP 请求之后添加一个限制/等待时间(指定的毫秒数)。

messageSchema.pre("insertMany", async function save(next, docs) {
      docs.map(async (doc) => { // now I understand I should replace map with for ... of or for ... in
        [err, response] = await to(
            reverseGeocode(
              doc.location.coordinates[0],
              doc.location.coordinates[1]
            )
        );
        if (err) {
          next(err);
        }
        doc.location.geocoded = response;
      });
    });

reverseGeocode 签名:

  reverseGeocode: (lon, lat) =>
    axios({
      baseURL: "https://eu1.locationiq.com/",
      url: "v1/reverse.php",
      params: {
        lat,
        lon,
        key: geocodeKey,
      },
    }).then((response) => response.data),

标签: node.jsmongodbpromiseasync-await

解决方案


我使用这个库来限制请求。您只需告诉它 API 的速率限制是多少,您就可以随心所欲地调用它,它会随着时间的推移自动为您分配请求。

如果您不想要另一个依赖项,那么要使您的解决方案工作,您需要使用for循环。map将始终尽可能快地执行。

const wait = (time) => {
  return new Promise((resolve) => {
    setTimeout(resolve, time);
  });
}

messageSchema.pre("insertMany", async function(next, docs) {
  for(let i in docs) {
    const doc = docs[i];
    await wait(3000); // milliseconds to space requests out by.
    const response = await reverseGeocode(
      doc.location.coordinates[0],
      doc.location.coordinates[1]
    );
  }
  console.log(this);
});

推荐阅读