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

Tim*_*imo 17 rest http bigdata mongodb node.js

我在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');
Run Code Online (Sandbox Code Playgroud)

内存不足时失败.该示例使用node-mongodb-native驱动程序和基本http包.

致命错误:CALL_AND_RETRY_2分配失败 - 处理内存不足

(请注意,在实际场景中,我使用的参数会根据需要限制结果,但是此示例会查询所有这些最糟糕的情况,无论如何)

数据本身很简单,就像

{"_ id":ObjectId("4f993d1c5656d3320851aadb"),"userid":"80ec39f7-37e2-4b13-b442-6bea57472537","user-agent":"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));
  });
}
Run Code Online (Sandbox Code Playgroud)

但是那个内存也用完了.

我该怎么办?应该有一种逐行流式传输数据的方法,但是我找不到合适的例子.由于外部应用程序的要求,对数据进行分页是不可能的.我想过将数据写入文件然后发布,但这会导致不需要的io.

小智 15

cursor.streamRecords()本机的方法MongoDB驱动程序已经过时,该方法stream()是更快.

我已经解析了40,000,000行的acatalog文档而没有Mongodb+ stream()+的问题process.nextTick()


Tim*_*imo 8

我发现node-mongodb-native Cursor对象也有一个流选项(用于collection.find().streamRecords()),即使在驱动程序github页面中没有提到它也是如此.请参阅Cursor源代码并搜索"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();
  });
});
Run Code Online (Sandbox Code Playgroud)


ale*_*lex 5

类似的东西应该有效。如果没有,您可能应该在mongodb-native bug tracker中打开一个问题。

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);
Run Code Online (Sandbox Code Playgroud)

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