【问题标题】:Stream from a mongodb cursor to Express response in node.js从 mongodb 游标流式传输到 node.js 中的 Express 响应
【发布时间】:2013-12-02 05:48:59
【问题描述】:

我正在玩弄所有花哨的 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(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

根据mongodb driver doc, 我试图将此转换器传递给stream()

function(obj) {return JSON.stringify(obj);}

但这无济于事。

谁能告诉我如何正确地将某些内容流式传输到响应中?

或者是唯一的解决方案是使用“数据”和“结束”事件手动抽取数据的样板?

【问题讨论】:

  • 如果将catalog.byTag替换为直接调用MongoDB原生驱动,是否有效?
  • 不,同样的错误。另外,我可以调用toArray() 并通过res.json() 发送它,这是可行的,但我更喜欢流式传输而不是在服务器上缓冲然后再发送出去。

标签: node.js mongodb express


【解决方案1】:

将光标流与JSONStream 结合使用,将其通过管道传送到您的响应对象。

cursor.stream().pipe(JSONStream.stringify()).pipe(res);

【讨论】:

  • (并确保您之前res.set('Content-Type', 'application/json');,否则您的回复将被解释为文本。)
【解决方案2】:

此处是其他答案的有效组合

app.get('/comments', (req, res) => {
  Comment.find()
    .cursor()
    .pipe(JSONStream.stringify())
    .pipe(res.type('json'))
})

http://mongoosejs.com/docs/api.html#query_Query-cursor

  • cursor() 返回一个与 Node 流3 兼容的流,并且优先于已弃用的 query.stream() 接口。
  • 通过管道连接到 JSONStream.stringify() 以将文档组合成一个数组而不是单个对象
  • 通过管道连接到 res.type('json'),它将 HTTP Content-Type 标头设置为 application/json 并再次返回自身(响应流)。

【讨论】:

  • 这不会产生有效的 JSON,但是,它只是将字符串化的对象连接在一起,而不是将其正确包装在一个数组中。
  • @robertklep 你是对的!我不知道。谢谢!
  • 由于我们处理的是express,这里似乎需要一些错误处理。我想看看一些推荐的模式。
  • @robertklep 对于有效的 JSON 输出,还有什么替代方案?
  • @Tiago 当前答案将起作用(我的评论提到了已被编辑和修复的答案的先前版本)。
【解决方案3】:

简单。 .stream({transform: JSON.stringify});

【讨论】:

    【解决方案4】:

    您的 mongo 流正在将对象转储到只能处理字符串或缓冲区的 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)
    

    希望对你有帮助

    【讨论】:

      【解决方案5】:

      使用猫鼬和快递:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-02
        • 2020-10-05
        • 2012-06-18
        • 1970-01-01
        • 2018-02-19
        • 1970-01-01
        相关资源
        最近更新 更多