如何使用json响应创建另一个URL。的NodeJS

时间:2017-12-20 08:00:19

标签: javascript node.js mongodb parsing promise

我有问题,代码如下:

问题是:

  1. 如何将每行从回复promiseGetCitiesData发送到promiseGetInformationDataPerCity
  2. 我可以在一个async.each函数中完成吗?
  3. 现在,我创建了多个Promise函数。一个通用函数,一个启动程序 - getDataAndCloseDb()

    我还使用async.each使用数组参数调用promise函数 - locationArray

    现在,我想将每一行从json响应发送到下一个promise函数(create get url),并收集一般响应。

    const MongoClient = require("mongodb").MongoClient;
        const request = require("request");
        const async = require("async");
    
        var locationsArray = [
          'location1',
          'location2',
          'location3'
        ];
    
        function promiseConnectToDatabase(urldb) {
          return new Promise(function(resolve, reject) {
            MongoClient.connect(urldb, (err, db) => {
              if (err) {
                console.log("MongoDb connection error.");
                reject(err);
              }
              console.log("Connected to MongoDb.");
              resolve(db);
            });
          });
        }
    
        function promiseGetCitiesData(location) {
          return new Promise(function(resolve, reject) {
            request({
              url: `https://example.com/${location}`,
              json: true
            }, (error, response, body) => {
              if (error) {
                console.log("Error connection to url.");
                reject();
              }
              console.log("location: " + location);
              console.log({location: location, cities: body.result.cities});
              resolve({location: location, cities: body.result.cities});
            });
          });
        }
        /*
        Example response from promiseGetCitiesData:
    
        Location: location1
        { location: 'location1',
          cities: 
           [ 'information1',
             'information2',
             'information3',
             'information4'' ] }
    
        */
    
        function promiseGetInformationDataPerCity(location, cities) {
          return new Promise(function(resolve, reject) {
            request({
              url: `https://example.com/${location}/${cities}`,
              //f.e https://example.com/location1/information1 etc.
              json: true
            }, (error, response, information) => {
              if (error) {
                console.log("Error connection to url.");
                reject();
              }
              console.log(information);
              resolve(information);
            });
          });
        }
    
        function promiseSaveDataToDatabase(db, body) {
          return new Promise(function(resolve, reject) {
            db.collection("testlocation").insert(body, function(dbError) {
              if (dbError) {
                reject(dbError);
              }
              resolve()
            });
          });
        }
    
        function promiseDisconnectDatabase(db) {
          return new Promise(function(resolve, reject) {
            db.close((err) => {
              if (err) {
                console.log("MongoDb disconnect error.");
                reject(err);
              }
              console.log("MongoDb disconnected.");
              resolve();
            });
          });
        }
    
        function promiseProvideDataFromEach(locationsArray, db) {
          return new Promise(function(resolve, reject) {
            async.each(locationsArray, function(loc, locProcessedCb) {
              promiseGetcitiesData(loc).then(function(resultscities) {
                promiseGetInformationDataPerCity(loc, resultscities).then(function(resultDetails) {
                    promiseSaveDataToDatabase(db, resultDetails).then(function() {});
                locProcessedCb();
                });
              });
            }, function(err) {
              if (err) {
                locProcessedCb(err);
                reject(err);
              }
              console.log("All locations have been processed.");
              resolve();
            });
          });
        }
    
        function getDataAndCloseDb() {
          return new Promise(function(resolve, reject) {
            promiseConnectToDatabase("mongodb://127.0.0.1:27017/testApp").then(function(db) {
              promiseProvideDataFromEach(locationsArray, db).then(function() {
                promiseDisconnectDatabase(db).then(function() {});
              });
            });
          });
        }
    
        getDataAndCloseDb();
    

2 个答案:

答案 0 :(得分:1)

我认为这比问题中的代码更容易出现。特别是,new Promise(...)可以通过以下方式完全避免:

  • 使用require('async-request')代替require('request')
  • 允许MongoDb方法返回Promise,因为如果没有传递回调,很多人都会这样做。

另外

  • 使用Promise.all(array.map(...))模式,require('async')的需求消失。
  • https://stackoverflow.com/a/28915678/3478010 - 提供了一个很好的小型可重用处置器实用程序,在这里很有用。
  • 请记住从每个.then()回调中返回一个promise /值,该回调本身是异步的和/或应该传递数据。

有些猜测,我想你想要这样的东西:

const MongoClient = require('mongodb').MongoClient;
const request = require('async-request'); // just like `request()` but returns a promise

var locationsArray = [
    'location1',
    'location2',
    'location3'
];

function promiseGetCitiesData(loc) {
    return request({
        url: `https://example.com/${loc}`,
        json: true
    }).then(body => body.result.cities);
}

function promiseGetInformationDataPerCity(loc, cities) {
    return Promise.all(cities.map(city => {
        return request({
            'url': `https://example.com/${loc}/${city}`,
            'json': true
        }).then(cityInfo => ({ 'name':city, 'info':cityInfo }));
    }));
}

function promiseProvideDataFromEach(locationsArray, db) {
    return Promise.all(locationsArray.map(loc => {
        return promiseGetCitiesData(loc)
        .then(cities => promiseGetInformationDataPerCity(loc, cities)
        .then(citiesWithCityInfo => ({ 'location':loc, 'cities':citiesWithCityInfo }));
    }))
    .then(resultDetails => db.collection('testlocation').insertMany(resultDetails));
}

// disposer utility - credit: https://stackoverflow.com/a/28915678/3478010
function withDb(work) {
    var _db;
    return MongoClient.connect("mongodb://127.0.0.1:27017/testApp")
    .then((db) => {
        _db = db; // keep reference 
        return work(db); // perform work on db
    }).finally(() => {
        if (_db)
            _db.close();
    });
}

withDb(db => promiseProvideDataFromEach(locationsArray, db))
.then(() => {
    // connection released here
});

猜测工作主要围绕在db.collection('testlocation').insertMany(resultDetails)插入的内容。问题中的代码只给出了一个线索。我的尝试似乎很合理,但可能不是你想要的。准备好在promiseProvideDataFromEach()promiseGetInformationDataPerCity()进行一些更改。

答案 1 :(得分:0)

你可以做这样的事。它是一个更简单的代码,但我认为你可以将它映射到你当前的代码。

const Promise = require('bluebird')

const cities = ['citya', 'cityb', 'cityc']

function resolveCities() {
  return new Promise(function(resolve, reject) {
    resolve(cities)
  })
}

function logCity(city) {
  console.log('city ', city)
}

return resolveCities() 
.then(function(cities) {
  return Promise.mapSeries(cities, function(city) {
    logCity(city);
  });
})