Node.jsで複雑なJSON応答を返す方法は?


82

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

回答:


183

Express 3では、res.json({foo:bar})を直接使用できます。

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

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


9
エクスプレスなしでそれを行う方法は?
piotrek 2014

@ Ludwik11 res.write(JSON.stringify(foo))。がfoo大きい場合は、切り刻む必要がある場合があります(文字列化してから、一度にチャンクを書き込みます)。おそらく、必要に"Content-Type":"application/json"応じてヘッダーなども設定する必要があります。
OJFord 2015

21

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

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

12

[編集] 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 })));

これは良い考えです。しかし、それは私には少しハッキーに見えます。nodejsがもう少しエレガントなものを提供することを望んでいました。
マーティン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.