【问题标题】:Closing mongodb connection in node.js after inserting many documents插入许多文档后在node.js中关闭mongodb连接
【发布时间】:2014-01-02 01:42:30
【问题描述】:

有人问过这个问题,但 OP 接受的答案没有满足我的特殊需求。

closing mongodb connection in node.js while inserting lot of data

我有一个实用程序脚本,可以将大量记录添加到多个集合中。实际上,它只是一个使用 byline 读取 VERY LARGE 文本文件然后将数据插入到集合中的导入:

var MongoClient = require("mongodb").MongoClient;
var fs = require("fs");
var byline = require("byline");

var inStream = fs.createReadStream("data.txt", { encoding: "utf8" });

var byLineStream = byline.createStream(inStream);

MongoClient.connect("mongodb://localhost:27017/test", { native_parser: true}, function(err, db) {  
    var collection = db.collection("Data");
    db.dropCollection("Data", function(err, result) {
        byLineStream.on("data", function(line) {
            var o = parseLineToObject(line);
            collection.insert(o);
        });
    });
});

建议的答案是将所有数据推送到一个数组中,然后在完成后使用单次写入和回调来关闭数据库。这不是一个好的答案,因为我正在处理的文件非常大,因此会消耗大量内存。

另一个类似question 的解决方案是使用async 包创建一个函数数组,然后并行运行它们。另一个半身像,但至少它不会创建一个巨大的单个插入。

所以问题是:如何在所有插入完成后关闭 MongoDB 连接,以便我的脚本退出并且不会挂起?

我应该补充一点,我已经尝试过在插入回调中增加计数器变量的计数方法。它不起作用,因为在插入的某个时刻,回调执行和完成的速度比插入完成的速度快,导致计数器在插入仍在进行时达到 0,从而关闭数据库。

【问题讨论】:

    标签: node.js mongodb


    【解决方案1】:

    当所有行都被读取时,你应该设置一个标志:

    var readAllLines = false;
    
    byLineStream.on("end", function() {
      readAllLines = true;
    });
    

    接下来,您在插入每条记录后检查该标志。但是,您还需要跟踪已读取的行数以及插入的行数,因此只有在所有行都已插入(甚至是乱序)时才关闭数据库。

    把所有东西放在一起:

    db.dropCollection("Data", function(err, result) {
      var lineCount     = 0;
      var readAllLines  = false;
    
      byLineStream.on("end", function() {
        readAllLines = true;
      });
    
      byLineStream.on("data", function(line) {
        lineCount++;
        var o = parseLineToObject(line);
        collection.insert(o, { w : 1 }, function() {
          if (--lineCount === 0 && readAllLines) {
            // we've read and inserted all lines
            db.close();
          }
        });
      });
    });
    

    但是,我确实相信将回调传递给 insert(“安全模式”)比您当前的解决方案慢,在当前解决方案中您调用 insert 但不要等待它的结果。为了加快速度,您可以在将它们插入一条语句之前缓冲 X 行,而不是单独编写每一行。

    类似的东西(不计行数):

    var buffer = [];
    byLineStream.on("data", function(line) {
      buffer.push(parseLineToObject(line));
      if (buffer.length > 100 || readAllLines) {
        collection.insert(buffer, { w : 1 }, function() {
          if (readAllLines) {
            db.close();
          }
        });
        buffer = [];
      }
    });
    

    【讨论】:

    • 昨晚我一直在努力,这也是我想出的解决方案,但是它需要一个行计数器来确定写入是否完成:insertCount === 0 && readAllLines 它会关闭挂起的连接没有它就写。我将在不同的答案中发布该变体,如果您能更新您的答案以反映它,我将不胜感激。
    • @NathanielJohnson 我已经编辑了我的答案,请注意,您还需要跟踪实际插入的行数:)
    【解决方案2】:
    var MongoClient = require("mongodb").MongoClient;
    var fs = require("fs");
    var byline = require("byline");
    
    var inStream = fs.createReadStream("data.txt", { encoding: "utf8" });
    
    var byLineStream = byline.createStream(inStream);
    
    MongoClient.connect("mongodb://localhost:27017/test", { native_parser: true}, function(err, db) {  
        var collection = db.collection("Data");
        db.dropCollection("Data", function(err, result) {  //I am completely replacing collection
            var insertCount = 0;
            var doneReadingFile = false;
            byLineStream.on("end",function(line) {
                doneReadingFile = true;
            });
            byLineStream.on("data", function(line) {
                var o = parseLineToObject(line);
                collection.insert(o,function(err, result) {
                    insertCount--;
                    if (insertCount === 0 && doneReadingFile) {
                        db.close();
                    }
                });
            });
        });
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 2016-10-14
      • 2022-10-06
      • 2013-06-03
      相关资源
      最近更新 更多