Nodejs,通过回调关闭mongo db连接

时间:2017-12-15 20:14:14

标签: javascript node.js mongodb asynchronous callback

我遇到了回调,异步思维等问题。

执行计划:

  
      
  1. 连接到mongoDb。
  2.   
  3. 创建网址 - https://example.com +从locArray添加部分。
  4.   
  5. 发送获取请求(每个)。
  6.   
  7. 将数据保存到mongo db。
  8.   
  9. 关闭连接。
  10.   

问题:

  • 如果连接在jsonDataFromApi的最后一行关闭 - "服务器实例池被销毁"在将每个请求的所有数据保存到db

  • 之前
  • 因此callback(db)被发送到其他地方 - closeMongoDb

  • 但出现了错误
      

    "无法阅读财产'关闭'未定义"。

我认为,问题在于异步,发送回调等。

    const MongoClient = require('mongodb').MongoClient;
        const Array = require('node-array');
        const request = require('request');

        var locationArray = [
          'location1',
          'location2',
          'location3',
          'location4'
        ];

        var dataFromLocApi = (loc, callback) => {
          request({
            url: `https://example.com/${loc}`,
            json: true
          }, (error, response, body) => {
            if (error){
            callback('Error connection to url.');
            } else{
            callback(undefined, body.result);
          }
         });
        };

        var jsonDataFromApi = (urldb, callback) => {
        MongoClient.connect(urldb, (err, db) => {
          if (err) {
            console.log('MongoDb connection error.');
          }
          console.log('MongoDb - connected.');
          locationArray.forEachAsync(function(loc, index, arr) {
            dataFromLocApi(loc, (errorMessage, results) => {
              if (errorMessage) {
                console.log(errorMessage);
              } else {
                console.log(JSON.stringify(results, undefined, 2));
                db.collection('testCollection').insert(results, function(error, record) {
                  if (error)
                    throw error;
                  console.log("data saved");
                });
              }
            });

          }, function() {
            console.log('complete');
          });
        callback(db);
        });
        }

var closeMongoDb = (urldb, callback) => {
    jsonDataFromApi(urldb, (error, db) => {
      if (error){
        callback('Close connection - failure');
      } else{
        db.close();
        console.log('MongoDb connections was closed.');
    }
    });
    }

    closeMongoDb('mongodb://127.0.0.1:27017/testDb', (err, db) => {

      console.log('DONE');
    } );

1 个答案:

答案 0 :(得分:1)

那里的异步确实存在问题。 在调用db.close()之前,您还没有等待处理的项目。

此外,您定义的函数具有不明确的语义。例如,函数closeMongoDb应该基本上关闭数据库及其。但这是另一项工作:获取数据并在之后关闭数据库。

此外,我可能会使用async模块而不是node-array,因为最后一个模块似乎可以解决其他问题。

我重构了代码。请阅读我的评论。我试图让它尽可能清楚。



const MongoClient = require("mongodb").MongoClient;
const request = require("request");
// We are going to use the async module
// This is a classical module to handle async behavior.
const async = require("async");

// As you can see this function accepts a callback
// If there is an error connecting to the DB
// it passes it up to the caller via callback(err)
// This is a general pattern
const connectToDb = function(urldb, callback) {
    MongoClient.connect(urldb, (err, db) => {
        if (err) {
            console.log("MongoDb connection error.");
            callback(err);
            return;
        }

        // If everything is OK, pass the db as a data to the caller.
        callback(undefined, db);
    });
};

// This method fetches the data for a single location.
// The logic with errors/data is absolutely the same.
const getData = (loc, callback) => {
    request(
        {
            url: `https://example.com/${loc}`,
            json: true
        },
        (error, response, body) => {
            if (error) {
                callback("Error connection to url.");
                return;
            }

            callback(undefined, body.result);
        }
    );
};

// This function goes over each location, pulls the data and saves it to the DB
// Last parameter is a callback, I called it allDataFetchedCb to make it clear
// that we are calling it after ALL the locations have been processed
// And everything is saved to the DB.
const saveDataFromLocations = function(locations, db, allDataFetchedCb) {
    // First param here is an array of items
    // The second one is an async function that we want to execute for each item
    // When a single item is processed we call the callback. I named it 'locProcessedCB'
    // So it's clear what happens.
    // The third parameter is a callback that is going to be called when ALL the items
    // have been processed.
    async.each(
        locations,
        function(loc, locProcessedCb) {
            getData(loc, (apiErr, results) => {
                if (apiErr) {
                    console.log(apiErr);
                    // Well, we couldn't process the item, pass the error up.
                    locProcessedCb(apiErr);
                    return;
                }

                console.log(
                    `Obtained the data from the api: ${JSON.stringify(
                        results,
                        undefined,
                        2
                    )}`
                );

                db.collection("testCollection").insert(results, function(dbError) {
                    if (dbError) {
                        // Also an error, we couldn't process the item.
                        locProcessedCb(dbError);
                        return;
                    }

                    // Ok the item is processed without errors, after calling this
                    // So we tell the async.each function: ok, good, go on and process the next one.
                    locProcessedCb();
                });
            });
        },
        function(err) {
            // We gonna get here after all the items have been processed or any error happened.
            if (err) {
                allDataFetchedCb(err);
                return;
            }

            console.log("All the locations have been processed.");

            // All good, passing the db object up.
            allDataFetchedCb(undefined, db);
        }
    );
};

// This function is an entry point.
// It calls all the above functions one by one.
const getDataAndCloseDb = function(urldb, locations, callback) {
    //Well, let's connect.
    connectToDb(urldb, (err, db) => {
        if (err) {
            callback(err);
            return;
        }

        // Now let's get everything.
        saveDataFromLocations(locations, db, (err, db) => {
            if (err) {
                callback(err);
                return;
            }

            // If somehow there is no db object, or no close method we wanna know about it.
            if (!db || !db.close) {
                callback(new Error("Unable to close the DB Connection."));
            }

            // Closing the DB.
            db.close(err => {
                // If there's no error err === undefined or null
                // So this call is equal to callback(undefined);
                callback(err);
            });
        });
    });
};

const locationArray = ["location1", "location2", "location3", "location4"];

// Finally calling the function, passing all needed data inside.
getDataAndCloseDb("mongodb://127.0.0.1:27017/testDb", locationArray, err => {
    if (err) {
        console.error(
            `Unable to fetch the data due to the following reason: ${err}`
        );
        return;
    }

    console.log("Done successfully.");
});




由于我没有网址等,因此我没有运行此代码。因此,请自行尝试并根据需要进行调试。