Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/392.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Can';t使用Node.js将大块数据填充到mongodb_Javascript_Node.js_Mongodb - Fatal编程技术网

Javascript Can';t使用Node.js将大块数据填充到mongodb

Javascript Can';t使用Node.js将大块数据填充到mongodb,javascript,node.js,mongodb,Javascript,Node.js,Mongodb,我被要求导入从全市许多站点收集的大量天气数据。每个站点有一台具有一个文件夹的计算机,该文件夹每5分钟同步到一个中央服务器。每天都会创建一个新文件。所以,基本上结构是这样的。 一个txt文件的格式为csv文件,第一行为字段,其余为数字 服务器上的文件夹\u |__site1\uuuu日期1.txt || uuu2.txt | |__site2\uuuu日期1.txt |__date2.txt 我编写了一个小型node.js应用程序,将这些数据填充到mongoDB中。然而,目前我们只有3个站点,但每

我被要求导入从全市许多站点收集的大量天气数据。每个站点有一台具有一个文件夹的计算机,该文件夹每5分钟同步到一个中央服务器。每天都会创建一个新文件。所以,基本上结构是这样的。 一个txt文件的格式为csv文件,第一行为字段,其余为数字

服务器上的文件夹\u
|__site1\uuuu日期1.txt
|| uuu2.txt
|
|__site2\uuuu日期1.txt
|__date2.txt
我编写了一个小型node.js应用程序,将这些数据填充到mongoDB中。然而,目前我们只有3个站点,但每个站点有近900个txt文件,每个文件包含24*20=288行(因为数据每5分钟记录一次)。我试图运行node应用程序,但在读取了第一个文件夹的大约100个文件后,程序崩溃,出现了内存分配失败的错误

我已经尝试了很多方法来改善这一点:

  • 将nodejs的内存大小增加到8GB=>更好,读取的文件更多,但仍然无法移动到下一个文件夹
  • 将某个变量设置为null,并在uach循环的末尾未定义(我使用下划线)=>没有帮助
  • 移动文件数组(使用fs.readdir),以便删除第一个元素=>也没有帮助
  • 有没有办法强迫js在每次读取完文件后清理内存? 谢谢

    更新1:我一次在每个文件夹中添加100个文件。这看起来很枯燥,但很有效,这就像是一次工作。但是,我仍然希望找到解决方案。

    尝试使用,而不是将每个文件加载到内存中

    我已经向您发送了一个使用流和异步I/o的实现

    这是其中的大部分:

    var Async = require('async');
    var Csv = require('csv-streamify');
    var Es = require('event-stream');
    var Fs = require('fs');
    var Mapping = require('./folder2siteRef.json');
    var MongoClient = require('mongodb').MongoClient;
    
    var sourcePath = '/hnet/incoming/' + new Date().getFullYear();
    
    Async.auto({
      db: function (callback) {
        console.log('opening db connection');
        MongoClient.connect('mongodb://localhost:27017/test3', callback);
      },
      subDirectory: function (callback) {
        // read the list of subfolder, which are sites
        Fs.readdir(sourcePath, callback);
      },
      loadData: ['db', 'subDirectory', function (callback, results) {
        Async.each(results.subDirectory, load(results.db), callback);
      }],
      cleanUp: ['db', 'loadData', function (callback, results) {
        console.log('closing db connection');
        results.db.close(callback);
      }]
    }, function (err) {
      console.log(err || 'Done');
    });
    
    var load = function (db) {
      return function (directory, callback) {
        var basePath = sourcePath + '/' + directory;
        Async.waterfall([
          function (callback) {
            Fs.readdir(basePath, callback); // array of files in a directory
          },
          function (files, callback) {
            console.log('loading ' + files.length + ' files from ' + directory);
            Async.each(files, function (file, callback) {
              Fs.createReadStream(basePath + '/' + file)
                .pipe(Csv({objectMode: true, columns: true}))
                .pipe(transform(directory))
                .pipe(batch(200))
                .pipe(insert(db).on('end', callback));
            }, callback);
          }
        ], callback);
      };
    };
    
    var transform = function (directory) {
      return Es.map(function (data, callback) {
        data.siteRef = Mapping[directory];
        data.epoch = parseInt((data.TheTime - 25569) * 86400) + 6 * 3600;
        callback(null, data);
      });
    };
    
    var insert = function (db) {
      return Es.map(
        function (data, callback) {
          if (data.length) {
            var bulk = db.collection('hnet').initializeUnorderedBulkOp();
            data.forEach(function (doc) {
              bulk.insert(doc);
            });
            bulk.execute(callback);
          } else {
            callback();
          }
        }
      );
    };
    
    var batch = function (batchSize) {
      batchSize = batchSize || 1000;
      var batch = [];
    
      return Es.through(
        function write (data) {
          batch.push(data);
          if (batch.length === batchSize) {
            this.emit('data', batch);
            batch = [];
          }
        },
        function end () {
          if (batch.length) {
            this.emit('data', batch);
            batch = [];
          }
          this.emit('end');
        }
      );
    };
    
    我已经使用streams更新了你的tomongo.js脚本。我还将其文件I/o更改为使用异步而不是同步

    我用小数据集对代码中定义的结构进行了测试,效果非常好。我使用900X文件和288X线对3XDIR进行了一些有限的测试。我不确定数据的每一行有多大,所以我加入了一些随机属性。它相当快。看看它如何与您的数据配合。如果它导致问题,您可以在执行大容量插入操作时尝试使用不同的写入关注点来限制它

    还可以查看其中一些链接,以了解node.js中有关流的更多信息:

    -具有许多流示例的工具


    这是一个非常有用的流模块。

    正如Robbie所说,流是解决这个问题的方法<应该使用code>fs.createReadStream()而不是
    .readFileSync()
    。首先,我要创建一个行读取器,该读取器采用路径和您想要拆分的任何字符串/正则表达式:

    linereader.js

    var fs = require("fs");
    var util = require("util");
    var EventEmitter = require("events").EventEmitter;
    
    function LineReader(path, splitOn) {
    
        var readStream = fs.createReadStream(path);
        var self = this;
        var lineNum = 0;
        var buff = ""
        var chunk;
    
        readStream.on("readable", function() {
    
            while( (chunk = readStream.read(100)) !== null) {
                buff += chunk.toString();
                var lines = buff.split(splitOn);
    
                for (var i = 0; i < lines.length - 1; i++) {
                    self.emit("line",lines[i]);
                    lineNum += 1;
                }
                buff = lines[lines.length - 1];
            }
        });
        readStream.on("close", function() {
            self.emit("line", buff);
            self.emit("close")
        });
        readStream.on("error", function(err) {
            self.emit("error", err);
        })
    }
    util.inherits(LineReader, EventEmitter);
    module.exports = LineReader;
    
    var LineReader = require("./linereader.js");
    var async = require("async");
    
    var paths = ["./text1.txt", "./text2.txt", "./path1/text3.txt"];
    var reader;
    
    async.eachSeries(paths, function(path, callback) {
    
        reader = new LineReader(path, /\n/g);
    
        reader.on("line", function(line) {
            var doc = turnTextIntoObject(line);
            db.collection("mycollection").insert(doc);
        })
        reader.on("close", callback);
        reader.on("error", callback);
    }, function(err) {
        // handle error and finish;
    })
    

    你能分享你阅读文本和输入mongo的代码吗?这里是github上的链接:谢谢你的建议,但我似乎无法让它工作,因为这些txt是原始数据,需要在放入monogodb之前进一步处理。流库没有完整的文档记录,所以我不确定如何集成到我的节点应用程序中。我需要将ulimit从1024增加到8192,以便ti工作。将它们全部添加到mongodb(大约700k条记录)大约需要一分钟的时间。非常感谢。啊,是的,我的ulimit设置为5120,因为我以前多次达到这些限制:)-如果一切正常,您可能希望合并我的拉取请求;)-如果你需要帮助,请在公共关系中告诉我。