72 votos

¿Cómo devolver una respuesta JSON compleja con Node.JS?

Usando nodejs y express, me gustaría devolver uno o múltiples objetos (Array) usando JSON. En el código de abajo devuelvo un objeto JSON a la vez. Funciona pero esto no es exactamente lo que quiero. La respuesta producida no es una respuesta JSON válida ya que tengo muchos objetos.

Soy consciente de que podría simplemente añadir todos los objetos a un Array y devolver ese Array específico en res.end. Sin embargo, me temo que esto podría llegar a ser pesado de procesar y de memoria intensiva.

¿Cuál es la forma correcta de lograr esto con nodejs? ¿Es query.each el método correcto a llamar?

app.get('/users/:email/messages/unread', function(req, res, next) {
    var query = MessageInfo
        .find({ $and: [ { 'email': req.params.email }, { 'hasBeenRead': false } ] });

    res.writeHead(200, { 'Content-Type': 'application/json' });   
    query.each(function(err, msg) {
        if (msg) { 
            res.write(JSON.stringify({ msgId: msg.fileName }));
        } else {
            res.end();
        }
    });
});

172voto

zobi8225 Puntos 1490

En express 3 puedes usar directamente res.json({foo:bar})

res.json({ msgId: msg.fileName })

Ver el documentación

17voto

danmactough Puntos 1992

No sé si esto es realmente diferente, pero en lugar de iterar sobre el cursor de la consulta, podrías hacer algo así:

query.exec(function (err, results){
  if (err) res.writeHead(500, err.message)
  else if (!results.length) res.writeHead(404);
  else {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.write(JSON.stringify(results.map(function (msg){ return {msgId: msg.fileName}; })));
  }
  res.end();
});

12voto

maerics Puntos 47743

[Editar] Después de revisar la documentación de Mongoose, parece que se puede enviar cada resultado de la consulta como un trozo separado; el servidor web utiliza codificación de transferencia en trozos por defecto por lo que todo lo que tienes que hacer es envolver un Array alrededor de los elementos para convertirlo en un objeto JSON válido.

Aproximadamente (sin probar):

app.get('/users/:email/messages/unread', function(req, res, next) {
  var firstItem=true, query=MessageInfo.find(/*...*/);
  res.writeHead(200, {'Content-Type': 'application/json'});
  query.each(function(docs) {
    // Start the JSON array or separate the next element.
    res.write(firstItem ? (firstItem=false,'[') : ',');
    res.write(JSON.stringify({ msgId: msg.fileName }));
  });
  res.end(']'); // End the JSON array and response.
});

Alternativamente, como mencionas, puedes simplemente enviar el contenido del Array tal cual. En este caso el cuerpo de la respuesta se almacenará en el buffer y se envían inmediatamente, lo que puede consumir una gran cantidad de memoria adicional (por encima de la necesaria para almacenar los propios resultados) para conjuntos de resultados grandes. Por ejemplo:

// ...
var query = MessageInfo.find(/*...*/);
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(query.map(function(x){ return x.fileName })));

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X