【问题标题】:Nodejs, close mongo db connection via callbackNodejs,通过回调关闭mongo db连接
【发布时间】:2017-12-15 20:14:14
【问题描述】:

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

执行程序:

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

问题:

  • 如果连接在 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');
    } );

【问题讨论】:

  • 能否也粘贴closeMongoDb的函数代码?
  • 都是代码,closeMongoDb不是函数。
  • 那是什么?
  • 我想启动脚本。所以我应该创建 closeMongoDb 函数并像在我的示例代码上一样运行它?
  • jsonDataFromApi 的末尾,您将db 作为第一个参数提供给回调。但在closeMongoDb调用中,回调将db作为第二个参数。

标签: javascript node.js mongodb asynchronous callback


【解决方案1】:

那里的异步肯定存在问题。 在致电db.close() 之前,您无需等待处理项目。

此外,您定义的函数具有不明确的语义。例如,函数closeMongoDb 基本上应该关闭数据库,仅此而已。但这里还有另一项工作:获取数据并随后关闭数据库。

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

我已经重构了代码。请阅读我的cmets。我尽量说清楚。

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.");
});

我没有运行此代码,因为我没有 URL 等。所以请自己尝试并在需要时进行调试。

【讨论】:

  • 谢谢你,完美。现在,我想,我了解回调,创建通用函数。也感谢您的“async.js”。非常有帮助,很棒的描述,对我来说很棒的一课。一个问题,有时(根据所有资源)我们写const getData = (loc, callback) =>。但另一次:const connectToDb = function(urldb, callback)cons X = function {}const X = ()=>{}有很大区别吗?如果我改变它,我认为,行为是一样的。当我应该使用函数时,箭头函数=> 时,这对我来说是有问题的。
  • @profiler 在这里,我使用了像(x) => x * 2 这样的箭头函数,只是作为普通functions 的简写。事实上,它们之间是有区别的。但在这种特殊情况下,它们的工作方式完全相同。你可以做一些谷歌搜索,比如“如何使用箭头函数”。或者这是给你的视频:youtu.be/J85lRtO_yjY
  • 完美运行!谢谢你的帮助。
猜你喜欢
  • 1970-01-01
  • 2022-12-21
  • 1970-01-01
  • 1970-01-01
  • 2019-11-27
  • 2015-12-17
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多