如何使用node.js http服务器从mongodb返回大量的行?

我在MongoDB中有一个用户数据库,我想通过JSON中的REST接口导出。 问题是在最坏的情况下,返回的行数已经超过200万。

首先我试过这个

var mongo = require('mongodb'), Server = mongo.Server, Db = mongo.Db; var server = new Server('localhost', 27017, {auto_reconnect: true}); var db = new Db('tracking', server); var http = require('http'); http.createServer(function (request, response) { db.collection('users', function(err, collection) { collection.find({}, function(err, cursor){ cursor.toArray(function(err, items) { output = '{"users" : ' + JSON.stringify(items) + '}'; response.setHeader("Content-Type", "application/json"); response.end(output); }); }); }); }).listen(8008); console.log('Server running at localhost:8008'); 

当内存不足时会失败。 该示例使用node-mongodb-native驱动程序和基本的http软件包。

致命错误:CALL_AND_RETRY_2分配失败 – 进程内存不足

(请注意,在实际情况下,我使用的参数会根据需要限制结果,但是本示例将查询所有最糟糕的情况)

数据本身很简单,就像

{“_id”:ObjectId(“4f993d1c5656d3320851aadb”),“userid”:“80ec39f7-37e2-4b13-b442-6bea57472537”,“用户代理”:“Mozilla / 4.0(兼容; MSIE 8.0; Windows NT 5.1; Trident / 4.0; .NET CLR 1.1.4322)“,”ip“:”127.0.0.1“,”lastupdate“:1335442716}

我也试过类似的东西

 while(cursor != null) { cursor.nextObject(function(err, item) { response.write(JSON.stringify(item)); }); } 

但是那个记忆也没有了。

我应该如何继续? 应该有一种方法可以逐行地对数据进行stream式处理,但是我还没有find合适的例子。 由于外部应用程序需求,分页数据不存在问题。 我想将数据写入一个文件,然后发布,但这导致不需要的io。

       

网上收集的解决方案 "如何使用node.js http服务器从mongodb返回大量的行?"

本机MongoDB驱动程序的cursor.streamRecords()方法已弃用,方法stream()更快。

我已经parsing了一个40万行的acatalog文档,没有Mongodb + stream() + process.nextTick()

我发现node-mongodb-native Cursor对象也有一个stream选项(与collection.find().streamRecords() )一起用于logging,即使它没有在驱动程序的github页面中提到。 查看游标源代码并search“streamRecords”。

最后代码结束了这样的:

 db.collection('users', function(err, collection) { var first = true; response.setHeader("Content-Type", "application/json"); response.write('{"users" : ['); var stream = collection.find().streamRecords(); stream.on('data', function(item) { var prefix = first ? '' : ', '; response.write(prefix + JSON.stringify(item)); first = false; }); stream.on('end', function() { response.write(']}'); response.end(); }); }); 

像这样的东西应该工作。 如果不是的话,你可能应该在mongodb本地bug跟踪器中打开一个问题。

 http.createServer(function (request, response) { db.collection('users', function(err, collection) { collection.find({}, function(err, cursor){ response.setHeader("Content-Type", "application/json"); cursor.each(function(err, item) { if (item) { response.write(JSON.stringify(item)); } else { response.end(); } }); }); }); }).listen(8008); 

PS:这只是一个存根,我的意思是我不记得确切的语法,但它是你正在寻找的eachfunction。

那么,我不再使用mongodb原生的JavaScript驱动程序,但在mongoose有很好的实施stream。

这两个驱动程序的语法非常相似。 你可以用mongoose做这个:

 response.setHeader("Content-Type", "application/json"); var stream = collection.find().stream(); stream.on('data', function(doc) { response.write(doc); }); stream.on('close', function() { response.end(); }); 

使用Node的stream.Transform类来做一个小模块:

 var stream = require('stream'); function createCursorStream(){ var cursorStream = new stream.Transform({objectMode:true}); cursorStream._transform = function(chunk,encoding,done){ if(cursorStream.started){ cursorStream.push(', ' + JSON.stringify(chunk)); }else{ cursorStream.push('[' + JSON.stringify(chunk)); cursorStream.started = true; } done(); }; cursorStream._flush = function(done){ cursorStream.push(']'); done(); }; return cursorStream; } module.exports.streamCursorToResponse = function(cursor,response){ cursor.stream().pipe(createCursorStream()).pipe(response); }; 

你可以改变JSON.Stringify部分做任何其他types的“即时”转换来自mongodb光标的对象,并保存一些内存。