Stream from a mongodb cursor to Express response in node.js

I am toying around with all the fancy node.js/mongodb/express platforms, and stumbled across a problem:

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

     }
  });
});

As you probably guessed, catalog.byTag(tag, callback) does a find() query to Mongodb and returns the cursor

This leads to an error:

TypeError: first argument must be a string or Buffer

According to mongodb driver doc, I tried to pass this converter to stream():

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

but that does not help.

Can anybody tell me how to correctly stream something to a response?

Or is the only solution a boilerplate to manually pump the data using the 'data' and 'end' events?


Use the cursor stream in combination with JSONStream to pipe it to your response object.

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

A working combination of other answers here

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() returns a Node streams3 compatible stream and is preferred over the deprecated query.stream() interface.
  • Piping to JSONStream.stringify() to combine documents into an array instead of single objects
  • Piping to res.type('json') which sets the HTTP Content-Type header to application/json and returns itself (the response stream) again.

Simple. .stream({transform: JSON.stringify});