要件
・DBに格納されているデータをCSVでダウンロードできるようにする
・データはユーザーが回答したアンケートの結果
使用したモジュール
・json2csv
https://www.npmjs.com/package/json2csv
開発
1. データの成形
今回は、ユーザーが回答したアンケート結果をCSVとして出力したいと思いますので、表示する項目をユーザー名
、メールアドレス
、アンケート設問
、回答結果
とします。
// DBから出力したいデータを取得するconstdata=awaitgetData.getUserData(user_id);// データをJSON型に整える constgroupData=data.reduce((result,current)=>{// user_idごとにデータをまとめるconstelement=result.find((p)=>{returnp.id===current.user_id;});// user_idが既にあればquestionとanswerのみを追加するif(element){element.data.push({question:current.question,answer:current.answer});}else{// user_idが切り替わった時に新規の要素としてgroupDataに追加するresult.push({id:current.user_id,name:current.user_name,email:current.user_email,data:[{question:current.question,answer:current.answer,}],});}returnresult;},[]);
DBから取得したデータをJSONに成形しました。reduce関数を使っているのは1クエリで適切な形でデータを取得できなかったためなので、必須ではありません。for文やmap関数を使ってきれいにしてください。
reduce関数でのデータをグループ化は以下を参考にさせて頂きました。
参考サイト
JavaScript オブジェクト配列をsqlのgroup byのように集計する
成形したデータは以下のようになりました。dataの個数は同じでなくても大丈夫です。
[{id:267,name:"taro",email:"taro@example.com",data:[{question:"好きなプログラミング言語は?",answer:["HTML","CSS","JavaScript"]},{question:"得意なプログラミング言語は?",answer:["HTML","CSS"]},{question:"苦手なプログラミング言語は?",answer:["JavaScript"]}]},{id:269,name:"jiro",email:"jiro@example.com",data:[{question:"好きなプログラミング言語は?",answer:["Go","JavaScript"]},{question:"得意なプログラミング言語は?",answer:["PHP","Ruby"]},{question:"苦手なプログラミング言語は?",answer:["Java"]}]},]
2. JSONをCSVに変換
続いてJSONに成形したデータをCSVに変換していきます。今回はjson2csv
というモジュールを使用しました。他にもCSV系のモジュールはたくさんありましたので、自分にとって使いやすいものや仕様に沿っているものを選択すると良いかと思います。
const{Parser,transforms:{unwind}}=require('json2csv');functiongetCsv(data,fields,pathes,res){consttransforms=[unwind({paths:pathes,blankOut:true,})];constjson2csvParser=newParser({fields,transforms});constcsv=data.length?json2csvParser.parse(data):'';res.setHeader('Content-disposition','attachment; filename=data.csv');res.setHeader('Content-Type','text/csv; charset=UTF-8');returnres.send(csv);}module.exports=getCsv;
引数のdata
は先程成形したデータが渡ってきます。fields
にはdataの中の表示させたい項目を配列で渡します。今回の例ですと、以下のようになります。
constfields=['name','email','data.question','data.answer'];
questionとanswerはdataの入れ子になっているのでドット繋ぎにします。
最後のpathes
はdataの中でネストされている項目を配列で渡します。今回の例では以下のようになります。
constpathes=['data']
ここで、pathesの中にdata.answer
を入れると、answerに格納されている配列が展開されて表示されるようになります。今回は、一つの設問に対して複数の回答を1行で表示させたかったのでdataのみにしました。
他にも色々オプションがありますので、詳しくは公式ドキュメントを参照してください。
3. CSVの出力
後は、CSVに変換したデータをPOSTなどのルーティングでres.send
してあげることで、ブラウザからファイルをダウンロードすることができます。
constcsv=getCsv(groupData,fields,pathes,res);res.send(csv);
以上です。