web-dev-qa-db-ja.com

Node.jsで複雑なJSONレスポンスを返す方法は?

Nodejsとexpressを使用して、JSONを使用して1つまたは複数のオブジェクト(配列)を返します。以下のコードでは、一度に1つのJSONオブジェクトを出力します。それは動作しますが、これは私が望むものとはまったく異なります。私が多くのオブジェクトを持っているので、生成された応答は有効なJSON応答ではありません。

すべてのオブジェクトを単純に配列に追加し、res.endでその特定の配列を返すことができることをよく知っています。ただし、これは処理が重くなり、メモリを大量に消費する可能性があります。

Nodejsでこれを達成する適切な方法は何ですか? query.eachは呼び出すのに適切なメソッドですか?

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

エクスプレス3では、res.json({foo:bar})を直接使用できます

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

ドキュメント を参照してください

182
zobi8225

これが本当に違うかどうかはわかりませんが、クエリカーソルを反復処理するのではなく、次のようなことができます。

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

[編集]Mongooseのドキュメントを確認した後、各クエリ結果を個別のチャンクとして送信できるようです。 Webサーバーは チャンク転送エンコーディングデフォルト を使用するため、必要なことは、アイテムを有効なJSONオブジェクトにするために配列をラップするだけです。

大まかに(未テスト):

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

または、言及したように、単に配列の内容をそのまま送信することもできます。この場合、 応答本文はバッファリングされます すぐに送信され、大きな結果セットに対して(結果を保存するために必要な量を超える)追加のメモリを大量に消費する可能性があります。例えば:

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