我在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”,“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。
答案 0 :(得分:15)
不推荐使用本机cursor.streamRecords()
驱动程序的MongoDB
方法,
方法stream()
更快。
我在Mongodb
+ stream()
+ process.nextTick()
答案 1 :(得分:8)
我发现node-mongodb-native Cursor对象对于记录也有一个流选项(即collection.find().streamRecords()
}),即使在github page of the driver中没有提到它也是如此。请参阅Cursor source code并搜索“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();
});
});
答案 2 :(得分:4)
应该的工作。如果不是,您可能应该在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
函数。
答案 3 :(得分:2)
好吧,我不再使用mongodb本机javascript驱动程序,但在mongoose中有很好的流实现。
两个驱动程序的语法非常相似。你可以用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();
});
答案 4 :(得分:1)
使用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
个零件以做任何其他类型的"即时#34;转换来自mongodb光标的对象,并保存一些内存。