質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

899閲覧

Node.jsを使ってMySQLのSUM関数により取得した値をビューファイルで表示する方法

fujiyamaru

総合スコア1

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Node.js

Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2023/02/09 10:59

実現したいこと

  • Node.jsを使ってMySQLのSUM関数で取得した値をビューファイルで表示したい。

前提

初心者です。お忙しいところ見てくださりありがとうございます。
勉強のため、Node.jsを使って家計簿アプリを作成しています。
MySQLのデータから抽出したデータで「今月の支出合計」を表示したいのですが、viewファイルにうまく反映されません。
コマンドプロンプトにはconsole.logで正しい合計金額が表示されるため、関数の処理は間違っていないと考えます。
(multipleStatements: trueは記述済み)

どのようにしたらviewファイルに反映されるか、アドバイスをいただけますと幸いです。

発生している問題・エラーメッセージ

・エラーの表示はないが、
「今月の支出は 円です」という風に、値が表示されない。
その他生じた問題は「試したこと」にて後述いたします。

該当のソースコード

app.js

1app.get('/index', (req, res) => { 2 const select = 3 connection.query( 4 `SELECT * 5 FROM spendings 6 ORDER BY date DESC, id DESC; 7 SELECT SUM(price) 8 FROM spendings 9 WHERE DATE_FORMAT(date,'%Y%m') = DATE_FORMAT(NOW(),'%Y%m')`, 10 (error, results) => { 11 res.render('index.ejs', {spendings: results[0],sums: results[1]}); 12 } 13 ); 14});

index.ejs

1<div class="container-text"> 2 <h2>支出リスト</h2> 3 <h1>今月の支出は 4 <span class="sum"> 5 <%= sums['SUM(price)'] %> 6 </span> 7 円です 8 </h1> 9</div>

試したこと

①ソースコードに記載のとおり
結果→「今月の支出は 円です」のように、値が表示されない。

②index.ejs内の
<%= sums['SUM(price)'] %>

<%= sums %>とする
結果→「今月の支出は[object Object]円です」と表示される。

③index.ejs内の
<%= sums['SUM(price)'] %>

<%= JSON.stringify(sums) %>とする
結果→「今月の支出は [{"SUM(price)":1940}] 円です」
※1940は正しい合計数値です

その他にもいくつか記述方法を変えて試しましたが、表示は上の3つのパターンのいずれか
になりました。

補足情報(FW/ツールのバージョンなど)

環境Windows10、MySQL5.7、Node.js 18

拙い文章で恐縮ですが、何卒宜しくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuma.inaura

2023/02/09 15:11

配列要素の1番目を使わなければいかないとか、それ系だったりしませんか
fujiyamaru

2023/02/10 09:32

コメントをいただき、ありがとうございました。参考にさせていただきました。 問題についても、解決いたしました。
guest

回答1

0

ベストアンサー

質問文に対してシンプルに解決策を出すなら、
SQL文には列別名(as)が存在します。

SQL

1SELECT * 2FROM spendings 3ORDER BY date DESC, id DESC; 4SELECT SUM(price) as sum 5FROM spendings 6WHERE DATE_FORMAT(date,'%Y%m') = DATE_FORMAT(NOW(),'%Y%m')`

シンプルな列別名が与えられたので、簡単にアクセスできるようになりました。

ejs

1<div class="container-text"> 2 <h2>支出リスト</h2> 3 <h1>今月の支出は 4 <span class="sum"> 5 <%= sum %> 6 </span> 7 円です 8 </h1> 9</div>

ですが……
なんじゃこりゃ、SQLインジェクションを自分で引き起こしてるじゃん。
誰だよこんな書き方を質問者さんに勧めたヤツは。

https://www.npmjs.com/package/mysql#multiple-statement-queries

Multiple statement queries

Support for multiple statements is disabled for security reasons (it allows for SQL injection attacks if values are not properly escaped).
To use this feature you have to enable it for your connection:
和訳: 複数のステートメントのサポートは、セキュリティ上の理由から無効になっています (値が適切にエスケープされていない場合、SQL インジェクション攻撃が可能になります)。
この機能を使用するには、接続に対して有効にする必要があります。

2個のSQL文は個別に投げましょう。
その為のベストプラクティスまで解説していきます。

それを踏まえて手直しするとこんな感じ。

js

1app.get('/index', (req, res) => { 2 connection.query( 3 `SELECT * 4 FROM spendings 5 ORDER BY date DESC, id DESC;` 6 (err, spendings) => { 7 if (err) console.error(err); 8 connection.query( 9 `SELECT SUM(price) as sum 10 FROM spendings 11 WHERE DATE_FORMAT(date,'%Y%m') = DATE_FORMAT(NOW(),'%Y%m')`, 12 (err, results) => { 13 if (err) console.error(err); 14 res.render('index.ejs', {spendings, sum: results[0].sum}); 15 } 16 ); 17 } 18 ); 19});

2個のSQL文を投げるだけでご覧の有様です。
こういうコールバック関数を引数として渡す機能を使い、
それがネストしていってコードが汚れる事を「コールバック地獄」と呼びます。

これに関してはPromiseとasync/awaitを覚えましょう。


JavaScriptではコールバック地獄に対して
Promiseというオブジェクト指向プログラミングのテクニックを用いた解決策があり、
async/await構文というPromiseを上手く使って同期処理っぽく非同期処理を書ける構文も用意されています。
(ECMAScript2017という2017年のバージョンで追加されました)

そして世のコード・ライブラリの多くがPromise前提で書き直されていきました。
従来のコールバック関数を引数として渡す方法は古臭い手法になりつつあります。

Node.jsのmysqlもその一つで3年前からもうメンテナンスされておらず
作者はmysql2というライブラリへ移行しました。

mysql2ではPromiseを使った最新の書き方があるのでそちらも見ていきましょう。

bash

1$ npm install mysql2

プロジェクト説明のREADMEを眺めても使い方は分かりますが、
GitHubのexamplesにはより詳細な使い方が載っているのでそこから抜粋しつつ手直ししましょうか
https://github.com/sidorares/node-mysql2/tree/master/examples/promise-co-await

js

1const mysql = require('mysql2/promise'); 2 3// createConnectionがPromiseを返すようになっている 4// awaitしなければコネクションを取り出せなくなっている事に注意 5const connection = mysql.createConnection({host:'localhost', user: 'root', database: 'test'}); 6 7// await構文を使う為にはasync関数を定義しなければならない 8app.get('/index', async (req, res) => { 9 // promiseインスタンスにawait構文を使うと、 10 // promise.then(val => {})のvalを引っ張り出すのと同じ効果を得られる 11 const conn = await connection; 12 13 // tryはpromiseをawaitした時、promiseが失敗していた時にキャッチできるようになる 14 try { 15 const [spendings] = await conn.query(` 16 SELECT * 17 FROM spendings 18 ORDER BY date DESC, id DESC; 19 `); 20 const [results] = await conn.query(` 21 SELECT SUM(price) as sum 22 FROM spendings 23 WHERE DATE_FORMAT(date,'%Y%m') = DATE_FORMAT(NOW(),'%Y%m') 24 `); 25 res.render('index.ejs', {spendings, sum: results[0].sum}); 26 } catch (err) { 27 console.error(err); 28 } 29});

投稿2023/02/10 03:17

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fujiyamaru

2023/02/10 09:11

具体的なコードも含めた丁寧な回答をいただき、ありがとうございました。 単なる解決方法だけでなく、ベターなものを順を追って、論理的に説明していただいたので非常に分かりやすく、また、勉強になりました。 取り急ぎ2番目のコールバック地獄の書き方でも正しく表示されましたが、 Promiseとasync/awaitについて初めて知りましたので、自分でも咀嚼したのち、書き直してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問