如何从JSON文件目录中添加许多logging到mongoDB?

我有大约一百万个JSON文件保存在目录“D:/ njs / nodetest1 / imports / source1 /”的许多子目录中,我想将它们导入到我的mongoDB数据库的集合“users”中。

以下代码正确遍历文件系统。 正如你所看到的,它读取目录中的每个项目,如果该项目是一个目录,它读取每个项目。 对于不是目录的每个项目,它在发送一个variables来保存一个函数之前对它执行一些操作。

function traverseFS (path){ var files = fs.readdirSync(path); for (var i in files){ var currentFile = path + '/' + files[i]; var stats = fs.statSync(currentFile); if (stats.isFile()) runOnFile(currentFile); else traverseFS(currentFile); } } traverseFS("D:/njs/nodetest1/imports/source1/") 

接下来,我在代码上运行一些操作(见下文)。 这将读取文件,将其parsing为JSON对象,将该对象的两个属性读入variables,在variables“entry”中创build一个对象并将该variables传递给另一个函数。

 function runOnFile(currentFile){ var fileText = fs.readFileSync(currentFile,'utf8'); var generatedJSON = JSON.parse(fileText); var recordID = generatedJSON.recordID; var recordText = generatedJSON.recordTexts; var entry = {recordID:recordID, recordText:recordText}; insertRecord(entry); } 

最后的函数应该用来将数据插入到mongoDB中。 我认为这是事情出错的地方。

 function insertRecord(entry){ var MongoClient = mongodb.MongoClient; var MongoURL = 'mongodb://localhost:27017/my_database_name'; MongoClient.connect(MongoURL, function (err, db) { var collection = db.collection('users'); collection.insert([entry], function (err, result) { db.close(); }); }); } 

我预计这将通过文件结构运行,读取JSON文件到对象,然后将这些对象插入到我的mongoDB。 而是将第一个文件读入数据库,然后停止/挂起。

笔记:

  • 我不想使用mongoimport,因为我不想将这些文件中的所有数据插入到我的MongoDB数据库中。 然而,我并不拘泥于这种方法的任何方面。 如果存在其他解决scheme,我愿意接受。
  • 这连接到数据库就好了。 对于目录中的每个项目,这成功地创build“入口”对象并将其传递给insertRecord函数。 换句话说,这个问题必须发生在insertRecord部分。 但是这显然可能是由这个过程中的一些事情引起的。
  • 如果我添加error handling,则不会产生错误 。 我已经离开这个post的error handling,因为它混乱了代码片段的可读性。

根据mongodb 2.2(当前最新)文档 , insert已被弃用

弃用

使用insertOne,insertMany或bulkWrite

所以简短的答案可能是将collection.insert([entry], ...)更改为collection.insertOne(entry, ...)然后就完成了。


然后,对于长时间的答案,你会说“大约一百万个json文件”,这通常需要一个完整的asynchronous方法,并且花费最less。

示例代码中有两个(潜在的)瓶颈:

  • fs.readFileSync ,这是一个阻塞操作
  • 连接,插入一个logging和closures数据库连接

两者都被执行“大约一百万次”。 当然,导入通常不会一遍又一遍地完成(希望)不会在需要执行其他重要任务的机器上。 但是,示例代码可以很容易地变得更加健壮。

考虑使用glob模块来获取json文件的列表。

 glob('imports/**/*.json', function(error, files) {...}) 

这为您提供了asynchronous方式的完整文件列表。

然后考虑连接数据库一次,插入一切,closures一次。

在样本中保持或多或less相同的步骤,我会build议这样的:

 var glob = require('glob'), mongodb = require('mongodb'), fs = require('fs'), MongoClient = mongodb.MongoClient, mongoDSN = 'mongodb://localhost:27017/my_database_name', collection; // moved this to the "global" scope so we can do it only once function insertRecord(json, done) { var recordID = json.recordID || null, recordText = json.recordText || null; // the question implies some kind of validation/sanitation/preparation.. if (recordID && recordText) { // NOTE: insert was changed to insertOne return collection.insertOne({recordID: recordID, recordText: recordText}, done); } done('No recordID and/or recordText'); } function runOnFile(file, done) { // moved to be async fs.readFile(file, function(error, data) { if (error) { return done(error); } var json = JSON.parse(data); if (!json) { return done('Unable to parse JSON: ' + file); } insertRecord(json, done); }); } function processFiles(files, done) { var next = files.length ? files.shift() : null; if (next) { return runOnFile(next, function(error) { if (error) { console.error(error); // you may or may not want to stop here by throwing an Error } processFiles(files, done); }); } done(); } MongoClient.connect(mongoDSN, function(error, db) { if (error) { throw new Error(error); } collection = db.collection('users'); glob('imports/**/*.json', function(error, files) { if (error) { throw new Error(error); } processFiles(files, function() { console.log('all done'); db.close(); }); }); }); 

注意:您可以收集多个“条目” – logging,以利用insertMany的多个插入的性能增益,但我感觉插入的logging比描述更复杂,如果处理不正确,它可能会产生一些内存问题。

只需将您的数据结构化为一个大对象数组,然后运行db.collection.insertMany 。

我build议你用Promise做这个:

 const Bluebird = require('bluebird'); const glob = Bluebird.promisify(require('glob')); const mongodb = require('mongodb'); const fs = Bluebird.promisifyAll(require('fs')); const Path = require('path'); const MongoClient = mongodb.MongoClient; const insertMillionsFromPath = Bluebird.coroutine(function *(path, mongoConnString) { const db = yield MongoClient.connect(mongoConnString); try { const collection = db.collection('users'); const files = yield glob(Path.join(path, "*.json")); yield Bluebird.map( files, Bluebird.coroutine(function *(filename) { console.log("reading", filename); const fileContent = yield fs.readFileAsync(filename); const obj = JSON.parse(fileContent); console.log("inserting", filename); yield collection.insertOne(obj); }), {concurrency: 10} // You can increase concurrency here ); } finally { yield db.close(); } }); insertMillionsFromPath("./myFiles", "mongodb://localhost:27017/database") .then(()=>console.log("OK")) .catch((err)=>console.log("ERROR", err)); 

为了工作,您需要安装以下软件包:

npm install --save mongodb bluebird glob

你将需要使用node.js版本6或更高 ,否则你将需要transpile你的JavaScript(由于function *()生成器的使用)。