Wie kann eine komplexe JSON-Antwort mit Node.js zurückgegeben werden?

82

Mit nodejs und express möchte ich ein oder mehrere Objekte (Array) mit JSON zurückgeben. Im folgenden Code gebe ich jeweils ein JSON-Objekt aus. Es funktioniert, aber das ist nicht genau das, was ich will. Die erzeugte Antwort ist keine gültige JSON-Antwort, da ich viele Objekte habe.

Mir ist klar, dass ich einfach alle Objekte zu einem Array hinzufügen und dieses bestimmte Array in res.end zurückgeben kann. Ich befürchte jedoch, dass dies schwer zu verarbeiten und speicherintensiv werden könnte.

Was ist der richtige Weg, um dies mit nodejs zu erreichen? Ist query.each die richtige Methode zum Aufrufen?

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

Antworten:

183

In Express 3 können Sie direkt res.json ({foo: bar}) verwenden.

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

Siehe die Dokumentation

zobi8225
quelle
9
wie geht das ohne express?
Piotrek
@ Ludwik11 res.write(JSON.stringify(foo)). Wenn es foogroß ist, müssen Sie es möglicherweise zerhacken (stringifizieren, dann Stück für Stück schreiben). Wahrscheinlich möchten Sie auch Ihren Header "Content-Type":"application/json"oder ähnliches nach Bedarf sehen.
OJFord
21

Ich weiß nicht, ob dies wirklich anders ist, aber anstatt über den Abfragecursor zu iterieren, können Sie Folgendes tun:

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

[Bearbeiten] Nachdem Sie die Mongoose-Dokumentation überprüft haben, können Sie jedes Abfrageergebnis als separaten Block senden. Der Webserver verwendet Transfer - Codierung chunked standardmäßig so alles , was Sie tun müssen , ist ein Array wickeln sich um die Elemente es ein gültiges JSON - Objekt zu machen.

Grob (ungetestet):

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

Alternativ können Sie, wie Sie bereits erwähnt haben, den Array-Inhalt einfach so senden, wie er ist. In diesem Fall wird der Antworttext sofort gepuffert und gesendet, wodurch möglicherweise eine große Menge zusätzlichen Speichers (über dem zum Speichern der Ergebnisse selbst erforderlichen Wert) für große Ergebnismengen verbraucht wird. Beispielsweise:

// ...
var query = MessageInfo.find(/*...*/);
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(query.map(function(x){ return x.fileName })));
Maerics
quelle
Das ist eine gute Idee. Allerdings sieht es für mich ein bisschen hackig aus. Ich hatte gehofft, dass nodejs etwas eleganteres bieten.
Martin