Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8695

【Node.js】Express.jsからMySQLのデータ加工、ejsへの受け渡し

$
0
0

目的

現在、MySQLの店舗データを編集できるアプリケーションを作成しています。Node.jsのexpress.jsを使用し、viewにはejsを利用しています。この記事では、初学者の私がつまずいた、パラメータの受け渡しについて記述します。

ずばり「企業一覧画面から、企業に属した店舗の一覧を表示させる」処理についてです。

一連の処理は、こんな感じです

企業一覧画面(ejsで表示)
→ 店舗名のリンクをクリック
→ express.js(app.js)でデータを加工
→ 加工したデータをejsに渡す
→ ejsで表示させる

参照

Express.js(node.js)からMySQLへの接続とCRUD操作
[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する
for 文と push メソッドを使って配列要素を複数生成

環境と周辺構造

・local (mac Big Sur)
・AWS MySQL

基本となるデータベースとの接続やCRUD処理の書き方等については、リンク先の記事で作成しました。そちらを参考にしてください!
Express.js(node.js)からMySQLへの接続とCRUD操作

テーブル構造

テーブルの相関関係はこのような形です。
account_masterが企業、shop_masterが企業が運営する店舗を示しています。
スクリーンショット 2021-03-13 16.43.05.png
テーブルの関係性を簡単に表すと、
account_master.account_id = shop_master.shop_account_idです。
企業側のaccount_idは店舗側のshop_account_idと同じことを意味しています。

画面イメージ

少し雑ですが、画面のイメージは以下の通りです。
・企業 一覧画面(account_master_index.ejs)
スクリーンショット 2021-03-13 16.55.27.png
・店舗一覧画面(shop_index)
スクリーンショット 2021-03-13 16.57.24.png
企業名リンクをクリックすると、店舗一覧画面に遷移します。

ディレクトリ構造

※現在、未完成のため一部のみ記載

account_app/
├── node_modules
├── views
│   ├── account_master_index.ejs
│   ├── edit.ejs
│   └── shop_index.ejs
├── .env
├── .gitignore
├── app.js
├── package.json
└── README.md

前提

参考サイトでは、簡易なテーブルのデータで作成されていたため、企業の一覧や、店舗の一覧は簡単に表示まで出来ました。しかし、企業に基づく店舗など関係性がちょっと複雑な場合、どう表示させればよいかが全く分かりませんでした。

先に企業一覧について、次に店舗一覧について記述します。

企業一覧画面

app.js

企業一覧画面は参考サイトを元に、テーブル名、select文を変えるだけでOKでした。※記述外の設定は参考サイトを参照ください。

//app.jsの企業一覧に関する部分app.get('/',(req,res)=>{constsql="select * from account_master where is_deleted = 0";con.query(sql,function(err,result,fields){if(err)throwerr;res.render('account_master_index',{account_master:result});});});

app.getは express.js によるアプリケーションのルート( 今回は、localhost:3000 )へのGETメソッドに対応します。con.queryでデータベースから取得します。取得するデータはconst sqlで表記した select文(解約していない企業の情報すべて)です。

例外処理を記述した後、res.renderの第一引数にデータを表示させたいテンプレートを設定し、第二引数に .ejs に渡す名前を指定します。この命名により、ejs側ではresultではなくaccount_masterを使って取得したデータを利用できます。

account_master_indx.ejs

一部抜粋した記述です。

//account_master_indx.ejsの中身
    <% account_master.forEach(function (value) { %>
    <tr>
      <td><%= account_id %></td>
  ★   <td><a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a></td>
      <td><%= value.account_email.split('*') %></td>
      <td><%= value.mail_requested %></td>
      <td><%= value.is_deleted %></td>
      <td><%= value.updated_at %></td>
      <td><%= value.account_form_url %></td>
      <td><a href="/edit/<%= value.ue_account_id %>">up</a></td>
    </tr>
    <% }); %>

参考サイトはforEachを使っていたため、そのまま使っています。<% %>や、<%= %>で処理を書くのか、 HTML として表示させるかを書きます。

★ここで4行目に注目
<a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a>で企業 id のパラメータをURLに指定しています。後にこれと同じURLにする処理を app.js 内に if 文で記述します。

ここからが今回の記事の本題です

ポイントとしては以下のとおりです。
・企業に基づく店舗一覧をいきなり呼び出すのではなく、まず店舗の全データを出す
・配列を新たに作成する
・for文、if文で条件指定する
・加工した店舗一覧のデータをejs側で呼び出す

app.jsでデータを加工する

失敗した考え方
店舗一覧画面を出そうした際に、まず企業一覧画面と企業の編集画面を参考にしました。というのも、編集画面は企業のaccount_idを自然に渡せていたからです。そのため、店舗一覧画面も企業一覧と編集画面のようにaccount_idを受け渡せないかと考えました。

そもそも、この↑部分の認識が間違っており、正しくはexpress.js側で処理したデータをejsで表示させる。つまり、ejsからgetメソッドで表示させる場合はejsかた値を受け渡すなどは行わないです。

成功した考え方
いきなり企業に紐づく店舗一覧を、expressで記述しそれをejs側で表示させるのではなく、まずapp.js内で先に店舗の全データを出します。そのデータを使って、必要な情報だけを載せた配列を新たに作成します。作成した配列をejs側で呼び出し、表示させます。

店舗一覧画面

店舗一覧画面に関する記述は以下のとおりです。

app.js

//上部に宣言を記載varshopDat;//app.jsの上部で、店舗の全データを取得con.query('select * from shop_master where is_deleted = 0;',function(error,results,fields){if(error)throwerror;shopDat=results;//shopDatに代入});~~(中略)~~//企業ごとの店舗一覧を取得しshop_index.ejsで表示させるためのデータ加工app.get('/shop_index/:shop_account_id',(req,res)=>{letshops=[];//新たな配列を作成for(leti=0;i<shopDat.length;i++){//※shopDat.lendgthは要変更if(req.params.shop_account_id==shopDat[i].shop_account_id){//URLパラメータの値を条件付けvartarget_shop={//配列に入れるオブジェクトデータを定義"shop_id":shopDat[i].shop_id,"shop_name_jp":shopDat[i].shop_name_jp,"shop_name_en":shopDat[i].shop_name_en,"shop_account_id":shopDat[i].shop_account_id,"is_deleted":shopDat[i].is_deleted,"updated_at":shopDat[i].updated_at};shops.push(target_shop)//空の配列shopsに.pushで追加}};res.render('shop_index',{shop_data:shops});//for文作成した配列をshop_dataと命名});

先に shopDat を宣言し、そこにMySQLから店舗の全データを代入します。店舗一覧画面を表示させる箇所に、 shops という新たな空の配列を作成します。更にi番目の shopDat のデータを保持させる target_shop というオブジェクトを作成します。shops.push(target_shop)を shops という空の配列に、 for 文で作成されたオブジェクトを追加して、加工データを作成します。

この時req.params.shop_account_id == shopDat[i].shop_account_idではURLに渡すパラメータと企業に紐づく店舗の情報を一致させるために記述しています。※shop_account_idは企業のアカウント id と同じです。

req.paramsはリクエストされたパスからパラメータを取得するに使う文字列です。
[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する

shop_index.ejs

//店舗一覧画面に関係する部分
    <% for (let i = 0; i < shop_data.length; i++) { %>
      <tr>
        <td><%= shop_data[i].shop_id %></td>
        <td><%= shop_data[i].shop_name_jp %></td>
        <td><%= shop_data[i].shop_name_en %></td>
        <td><%= shop_data[i].shop_account_id %></td>
        <td><%= shop_data[i].updated_at %></td>
        <td><a href="/edit/<%= shop_data[i].shop_id %>">更新する</a></td>
      </tr>
      <% }; %>

企業一覧画面ではforEachを使いましたが、こちらは for 文で表記しました。これで、企業に属する店舗の一覧を表示させることができました。

小技とつまずいたポイント

・出力したいデータが正しいかどうかをHTML(.ejs)でみたい
<%- JSON.stringify(shop_data) %>と記述することで見られます!

・JavaScriptのデータは配列[ ]の中にオブジェクト{ }をもつことができる。
→ MySQLに格納されているデータはオブジェクトだったので、連想配列かと思ってしまいましたが、JavaScriptは [{ name:aaa, email:xxx@yyyy}, { name:bbb, email:yyy@xxxx}, { }....]とできるようです。(要勉強)

・forとif文をに記述するのではなく、一つづつ書くこと
→ 処理を一気に書こうとして、ほしいデータをなかなか出すことが出来ませんでした。落ち着いて出力されたデータを見ながら、一つづつ解決するほうが結果早いですね。

・app.jsにて、if文のshopDatに[ i ]をもたせること
→ iをつけることに、なかなか気がつけませんでした。

まとめ

JavaScriptを勉強しはじめて3週間ほどですが、MySQLのデータを加工を実施しました!空の配列を作って、ほしいデータを作成をすることは初めての作業でしたが、なんとかうまく出来たので良かったです。途中で、配列なのか連想配列なのか迷ったりしたため中々答えにたどり着けませんでした。これが初学者の方のためになればと思います。

また、一部未完成・不十分な記述がありますので、ご教示いただけると幸いです!

以上


Viewing all articles
Browse latest Browse all 8695

Trending Articles