これはpg-promiseで簡単に行えます:
function buildTree(t) {
const v = q => t.any('SELECT id, value FROM votes WHERE question_id = $1', q.id)
.then(votes => {
q.votes = votes;
return q;
});
return t.map('SELECT * FROM questions', undefined, v).then(a => t.batch(a));
}
db.task(buildTree)
.then(data => {
console.log(data); // your data tree
})
.catch(error => {
console.log(error);
});
上記と同じですが、ES7 async
を使用します /待つコード> 構文:
await db.task(async t => {
const questions = await t.any('SELECT * FROM questions');
for(const q of questions) {
q.votes = await t.any('SELECT id, value FROM votes WHERE question_id = $1', [q.id]);
}
return questions;
});
// method "task" resolves with the correct data tree
API:マップ、任意、タスク、バッチ
関連する質問:
- pg-promiseで親と子のツリーを取得する
- pg-promiseを使用した条件付きタスク
また、単一のクエリのみを使用する場合は、PostgreSQL9.4以降の構文を使用して次の操作を実行できます。
SELECT json_build_object('id', q.id, 'content', q.content, 'votes',
(SELECT json_agg(json_build_object('id', v.id, 'value', v.value))
FROM votes v WHERE q.id = v.question_id))
FROM questions q
そして、pg-promiseの例は次のようになります:
const query =
`SELECT json_build_object('id', q.id, 'content', q.content, 'votes',
(SELECT json_agg(json_build_object('id', v.id, 'value', v.value))
FROM votes v WHERE q.id = v.question_id)) json
FROM questions q`;
const data = await db.map(query, [], a => a.json);
そして、あなたは間違いなくそのような複雑なクエリを外部SQLファイルに保持したいと思うでしょう。クエリファイルを参照してください。
結論
上記の2つのアプローチのどちらを選択するかは、アプリケーションのパフォーマンス要件に基づく必要があります。
- 単一クエリのアプローチは高速ですが、読みやすく、拡張するのがやや難しく、かなり冗長です
- マルチクエリアプローチは理解と拡張が容易ですが、実行されるクエリの数が動的であるため、パフォーマンスには優れていません。
更新-1
次の関連する回答は、子クエリを連結することにより、より多くのオプションを提供します。これにより、パフォーマンスが大幅に向上します。ネストされたループクエリを親の結果pg-promiseに結合します。
UPDATE-2
ES7 async
を使用して追加された別の例 /待つコード> アプローチ。