19

JSON の REST インターフェイス経由でエクスポートしたい mongodb にユーザー データベースがあります。問題は、最悪のシナリオでは、返される行の量が 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", "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));
  });
}

しかし、それもメモリを使い果たしました。

どのように進めればよいですか?行ごとにデータをストリーミングする方法があるはずですが、適切な例を見つけることができませんでした。外部アプリケーションの要件があるため、データのページングは​​問題外です。データをファイルに書き込んでから投稿することを考えましたが、それは不要な io につながります。

4

5 に答える 5

16

cursor.streamRecords()ネイティブMongoDBドライバーのメソッドは非推奨になり、メソッドはstream()より高速になりました。

Mongodb+ stream()+で問題なく、カタログの40,000,000行のドキュメントを解析しました。process.nextTick()

于 2012-12-12T19:45:33.727 に答える
9

driver の github ページにcollection.find().streamRecords()記載されていなくても、node-mongodb-native Cursor オブジェクトにはレコードのストリーミング オプション ( で使用) があることがわかりました。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();
  });
});
于 2012-05-14T04:36:52.570 に答える
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);

PS: これは単なるスタブです。つまり、正確な構文は覚えていeachませんが、探している関数です。

于 2012-05-11T07:25:03.767 に答える
3

まあ、私はもうmongodbネイティブjavascriptドライバーを使用していませんが、mongooseはストリームのかなり良い実装があります。

2つのドライバーの構文は非常に似ています。あなたはマングースでこれを行うことができます:

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();
});
于 2012-05-11T06:23:41.133 に答える
2

A little module to do that using Node's stream.Transform class:

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);
};

You can alter JSON.Stringify parts to do any other kind of "on the fly" transforms on the objects coming from mongodb cursor, and save some memory.

于 2014-03-25T11:13:14.440 に答える