我在目录的许多子目录中保存了大约一百万个JSON文件" D:/ njs / nodetest1 / imports / source1 /"我想将它们导入集合"用户"在我的mongoDB数据库中。
以下代码正确遍历文件系统。如您所见,它会读取目录中的每个项目,如果该项目是目录,则会读取其中的每个项目。对于不是目录的每个项目,它在发送持有函数的变量之前对其执行一些操作。
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/")
接下来,我对代码运行一些操作(见下文)。这将读取文件,将其解析为JSON对象,将该对象的两个属性读入变量,在变量" entry"中创建一个对象。并将变量传递给另一个函数。
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中。相反,它将第一个文件读入数据库,然后停止/挂起。
注意:
答案 0 :(得分:8)
根据mongodb
2.2 (current latest) documentation,collection.insert([entry], ...)
已弃用
DEPRECATED
使用insertOne,insertMany或bulkWrite
因此,简短的回答可能是将collection.insertOne(entry, ...)
更改为fs.readFileSync
并且您已完成。
然后,对于长时间的回答,你会说“大约有一百万个json文件”,这通常需要一个完全异步的方法,而且开销最小。
示例代码中存在两个(潜在的)瓶颈:
glob('imports/**/*.json', function(error, files) {...})
,这是阻止操作两者都被执行“大约一百万次”。当然,导入通常不会一次又一次地进行,并且(希望)不会在需要其性能用于其他重要任务的机器上进行。尽管如此,示例代码仍然可以更加健壮。
考虑使用glob
模块获取json文件列表。
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();
});
});
});
这可以轻松地以异步方式为您提供完整的文件列表。
然后考虑只连接一次数据库,插入所有内容并关闭一次。
或多或少地保持样本中的步骤,我建议如下:
insertMany
注意:您可以使用import React from 'react';
import {
Text,
View
} from 'react-native';
const LoginPage = () => {
return (
<View>
<Text>
Welcome to React Native!
</Text>
</View>
);
}
export default LoginPage;
收集多个“条目”记录以利用多个插入的性能增益,但我感觉插入的记录比描述的更复杂,并且如果我认为它可能会产生一些内存问题没有正确处理。
答案 1 :(得分:2)
只需将数据组织成一个大的对象数组,然后运行db.collection.insertMany。
答案 2 :(得分:2)
我建议你使用Promises:
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或更高版本,否则您需要转换您的javascript(由于function *()
生成器使用)。