2012-01-18 34 views
79

Usando nodejs y express, me gustaría devolver uno o varios objetos (matriz) usando JSON. En el siguiente código, publico 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.¿Cómo devolver una respuesta JSON compleja con Node.js?

Soy consciente de que simplemente podría agregar todos los objetos a una matriz y devolver esa matriz específica en res.end. Sin embargo, me temo que esto puede ser pesado para procesar y memoria intensiva.

¿Cuál es la forma correcta de lograr esto con nodejs? ¿Es query.each el método correcto para 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(); 
     } 
    }); 
}); 

Respuesta

181

sobre el Express 3 se puede utilizar directamente res.json ({foo: bar})

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

Ver el documentation

+7

¿cómo hacer eso sin expresar? – Piotrek

+0

@ Ludwik11 'res.write (JSON.stringify (foo))'. Si 'foo' es grande, es posible que tenga que cortarlo (stringify, luego escriba trozo a la vez). Probablemente también quiera ver su encabezado '" Content-Type ":" application/json "' o similar, según corresponda. – OJFord

12

[Editar] Después de revisar la documentación de la mangosta, que parece que se puede enviar a cada resultado de la consulta como un trozo separado; el servidor web usa chunked transfer encodingby default por lo que todo lo que tiene que hacer es ajustar una matriz alrededor de los elementos para que sea un objeto JSON válido.

Aproximadamente (no probado):

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

alternativa, como usted menciona, sólo tiene que enviar el contenido de la matriz tal como está. En este caso, the response body will be buffered y enviado inmediatamente, que puede consumir una gran cantidad de memoria adicional (por encima de lo que se requiere para almacenar los resultados) para grandes conjuntos de resultados. Por ejemplo:

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

Esta es una buena idea. Sin embargo, me parece un poco raro. Esperaba que nodejs proporcionara algo un poco más elegante. – Martin

18

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

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