来自mongodb游标的流,用于在node.js中表示响应
我正在玩弄所有花哨的node.js/mongodb/express平台,偶然发现了一个问题:来自mongodb游标的流,用于在node.js中表示响应,node.js,mongodb,express,Node.js,Mongodb,Express,我正在玩弄所有花哨的node.js/mongodb/express平台,偶然发现了一个问题: app.get('/tag/:tag', function(req, res){ var tag=req.params.tag; console.log('got tag ' + tag + '.'); catalog.byTag(tag,function(err,cursor) { if(err) { console.dir(err); res.end
app.get('/tag/:tag', function(req, res){
var tag=req.params.tag;
console.log('got tag ' + tag + '.');
catalog.byTag(tag,function(err,cursor) {
if(err) {
console.dir(err);
res.end(err);
} else {
res.writeHead(200, { 'Content-Type': 'application/json'});
//this crashes
cursor.stream().pipe(res);
}
});
});
正如您可能猜到的,catalog.byTag(tag,callback)
对Mongodb执行find()
查询并返回光标
这将导致一个错误:
TypeError: first argument must be a string or Buffer
根据,,
我试图将此转换器传递到流()
:
但这没有帮助
有谁能告诉我如何正确地流式处理响应
或者,唯一的解决方案是使用“数据”和“结束”事件手动泵送数据的样板文件吗?您的mongo流正在将对象转储到res流中,而res流只能处理字符串或缓冲区(因此出现错误) 幸运的是,流很容易通过管道连接在一起,所以制作转换流来字符串化数据并不太难 在节点v0.10.21中:
var util = require('util')
var stream = require('stream')
var Transform = stream.Transform
util.inherits(Stringer, Transform)
function Stringer() {
Transform.call(this, { objectMode: true } )
// 'object mode allows us to consume one object at a time
}
Stringer.prototype._transform = function(chunk, encoding, cb) {
var pretty = JSON.stringify(chunk, null, 2)
this.push(pretty) // 'push' method sends data down the pike.
cb() // callback tells the incoming stream we're done processing
}
var ss = new Stringer()
db.createObjectStreamSomehow()
.pipe(ss)
.pipe(res)
希望这有助于将光标流与结合使用,将其输送到响应对象
cursor.stream().pipe(JSONStream.stringify()).pipe(res);
简单
.stream({transform:JSON.stringify})使用mongoose和express编码>:
function(req, res){
var stream = database.tracks.find({}).stream();
stream.on('data', function (doc) {
res.write(JSON.stringify(doc));
});
stream.on('end', function() {
res.end();
});
}
这里是其他答案的有效组合
app.get('/comments', (req, res) => {
Comment.find()
.cursor()
.pipe(JSONStream.stringify())
.pipe(res.type('json'))
})
cursor()
返回一个与节点streams3兼容的流,它比不推荐使用的query.stream()接口更可取
- 通过管道连接到
JSONStream.stringify()
,将文档合并到一个数组中,而不是单个对象
- 管道到
res.type('json')
,它将HTTP内容类型
头设置为应用程序/json
,并再次返回自身(响应流)
如果将catalog.byTag替换为对MongoDB本机驱动程序的直接调用,是否有效?否,相同的错误。另外,我可以调用toArray()
并通过res.json()
发送,这是可行的,但我更喜欢流式传输,而不是在服务器上缓冲并在之后发送(并且确保您在之前res.set('Content-Type','application/json');
,否则您的响应将被解释为文本)不过,这不会生成有效的JSON,它只是将字符串化的对象连接在一起,而不是将其正确地包装在数组中。@robertklep你说得对!我不知道。谢谢因为我们正在处理express,所以这里似乎需要一些错误处理。我想看看一些推荐的模式。@robertklep对于有效的JSON输出,有什么替代方案?@Tiago当前的答案将起作用(我的评论提到了答案的早期版本,该版本已被编辑和修复)。
app.get('/comments', (req, res) => {
Comment.find()
.cursor()
.pipe(JSONStream.stringify())
.pipe(res.type('json'))
})