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

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

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

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

Node.js

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

Q&A

解決済

1回答

1430閲覧

【node.js】for文と変数を使って、mysql文を表現したい

shibachi

総合スコア19

MySQL

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

Node.js

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

0グッド

0クリップ

投稿2020/10/13 02:37

やりたいこと

現在、node.jsで簡単なSNSアプリケーションを開発しており、ユーザーが過去に押した「いいね」のツイートを表示するということをやりたいです。そのために、mysqlでユーザーが過去に押した「いいね」のツイートのIDをDBから取得しようとしています。下の「ためしたこと」でも書いてありますが、sql文を表現しきっているはずなのになぜかうまくいかないです。

エラー文

Cannot read property 'forEach' of undefined at eval (C:\xampp\htdocs\sns_app\views\favorite.ejs:18:15) at favorite (C:\xampp\htdocs\sns_app\node_modules\ejs\lib\ejs.js:691:17) at tryHandleCache (C:\xampp\htdocs\sns_app\node_modules\ejs\lib\ejs.js:272:36) at View.exports.renderFile [as engine] (C:\xampp\htdocs\sns_app\node_modules\ejs\lib\ejs.js:489:10) at View.render (C:\xampp\htdocs\sns_app\node_modules\express\lib\view.js:135:8) at tryRender (C:\xampp\htdocs\sns_app\node_modules\express\lib\application.js:640:10) at Function.render (C:\xampp\htdocs\sns_app\node_modules\express\lib\application.js:592:3) at ServerResponse.render (C:\xampp\htdocs\sns_app\node_modules\express\lib\response.js:1012:7) at Query.connection.query (C:\xampp\htdocs\sns_app\app.js:131:17) at Query.<anonymous> (C:\xampp\htdocs\sns_app\node_modules\mysql\lib\Connection.js:526:10)

実装中のコード

javascript

1app.get('/favorite', (req, res) => { 2 var mysql1 = 'SELECT tweet_id FROM favorite WHERE user_id = ?'; 3 var mysql2 = 'SELECT * FROM tweets WHERE id = '; 4 var mysql3 = 'SELECT * FROM tweets WHERE id = 4 OR id = 3'; 5 6 connection.query( 7 mysql1, 8 [user_id], 9 (error,results)=>{ 10 for (var i = 1, len = results.length; i < len; ++i) { 11 mysql2 = mysql2 + results[0].tweet_id + ' OR id = ' + results[i].tweet_id; 12 } 13 console.log('mysql2>>',mysql2); 14 console.log('mysql3>>',mysql3); 15 }); 16 17 connection.query( 18 mysql2, 19 (error,results)=>{ 20 console.log('favorite>>',results); 21 res.render('favorite.ejs',{user:username,tweets:results,title:"お気に入り"}); 22 }); 23});//app.favorite

実装中のコード 

ejs

1<h3><%= title %></h3> 2 <a href="/new_tweet">新規追加</a> 3 <ul> 4 <% tweets.forEach((tweet) => { %> 5 <li class="tweet"> 6 <span class="tweet_content"><%= tweet.content %></span> 7 <% 8 var category; 9 var list =["恋愛","科学","仕事","日常","広告","PC","病院","漫画","映画","ゲーム","政治"]; 10 category = list[tweet.category]; 11 %> 12 <span class="category">#<%= category %></span> 13 <a href="#" class="good_btn"><%= tweet.good %></a> 14 </li> 15 <% }); %> 16 </ul>

ためしたこと

sql文がうまく表現できていないのかと思い、console.logに出力させたところ以下のようになりました。

mysql2>> SELECT * FROM tweets WHERE id = 4 OR id = 3 mysql3>> SELECT * FROM tweets WHERE id = 4 OR id = 3 favorite>> undefined ```mysql3となっているのは試しでベタ打ちで書いてみたものです。ちなみに、mysql3をqueryの中に入れると、ちゃんと作動します。 ### バージョン "dependencies": { "ejs": "^3.1.5", "express": "^4.17.1", "jquery": "^3.5.1", "mysql": "^2.18.1" }

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

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

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

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

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

firegrape

2020/10/13 03:56

勘違いだったらごめんなさい。 connection.queryって最初の引数に設定されたクエリが実行されるのではないのでしょうか? console.logに入れても実行されないと思うのですが、いかがでしょうか?
shibachi

2020/10/13 04:08

connection.queryの第一引数に設定されたクエリが実行されるのはそうです! 実際に設定もしております。 ------------------------------------------------------------------------ connection.query( mysql2, (error,results)=>{ console.log('favorite>>',results); res.render('favorite.ejs',{user:username,tweets:results,title:"お気に入り"}); });
shibachi

2020/10/13 04:20

そうですね… その質問の時はsql文がそもそも間違っていたので、ある意味よかったのですが、今回はsql文はおそらくあっているので、困っているという状態です…
firegrape

2020/10/13 04:23

以下の部分ですが、tweetsにはちゃんと値が入っているのは確認済みですか? >forEachがあるのはtweets.forEachの行ですね。 >tweetsは配列であるべきだったのにundefinedが入っている事が問題です。
shibachi

2020/10/13 04:35

mysql3でsql文をベタ打ちをしてみたものをqueryに入れて実行した場合は、問題なく動くので、値は入っているかと思います。 ためしで、mysql2の内容とmysql3のconsole.logの出力結果は同じなはずなので、原因がよくわからなくなっています。
firegrape

2020/10/13 04:48 編集

console.log(results); これやるとどうなりますか?
shibachi

2020/10/13 04:54

2つ目のqueryのほうですよね?? undefinedになっていますね
firegrape

2020/10/13 04:58

はい、ちなみにどこでresultsに値を代入しているのですか?
attakei

2020/10/13 05:07

コールバック関数の引数になっている。errorの中身を確認したほうが良いと思います。 仮にconnection.queryの処理に問題があったりした場合は、errorになにか入っていると思います
shibachi

2020/10/13 15:17

@firegrape 返信遅くなり、申し訳ないです。 すみません、質問の意図がわからないので、もう少し詳しくお願いできますでしょうか。
firegrape

2020/10/13 15:30

コールバック関数理解していないので、聞いてしまいました。 普通に考えたら、resultsに値が入っていないからforEach失敗するのかな と思っただけです。
shibachi

2020/10/13 15:32

@attakei エラーの内容はER_EMPTY_QUERY: Query was emptyとなっていますね...
shibachi

2020/10/13 15:40

@firegrape sql文を変数を使わないで、ベタ打ちをすると問題なく処理が走るのでresultsに値は入っているかと思います!
attakei

2020/10/13 16:53

> エラーの内容はER_EMPTY_QUERY: Query was emptyとなっていますね... 回答の方にも少し書いたんですが、これだと「クエリーが空」となっているために起きているようにも見えます。 2度目のconnection.queryの中で定義されているコールバック関数内だと、mysql2はどういう内容になっているかを確認するとどうなるでしょうか? ※console.log('favorite>>',results);のタイミングでresultsではなくmysql2を表示させてみた場合
guest

回答1

0

ベストアンサー

※簡単に動作を手元で見返して、わかる範囲での回答にはなります

対処としての回答

クエリの結果から更にクエリを組み立てるのであれば、コールバック関数内でconnection.queryを実行したほうが良いと思います。

diff

1app.get('/favorite', (req, res) => { 2 var mysql1 = 'SELECT tweet_id FROM favorite WHERE user_id = ?'; 3 var mysql2 = 'SELECT * FROM tweets WHERE id = '; 4 var mysql3 = 'SELECT * FROM tweets WHERE id = 4 OR id = 3'; 5 6 connection.query( 7 mysql1, 8 [user_id], 9 (error,results)=>{ 10 for (var i = 1, len = results.length; i < len; ++i) { 11 mysql2 = mysql2 + results[0].tweet_id + ' OR id = ' + results[i].tweet_id; 12 } 13 console.log('mysql2>>',mysql2); 14 console.log('mysql3>>',mysql3); 15+ connection.query( 16+ mysql2, 17+ (error,results)=>{ 18+ if (error) throw error; // SQLエラー時の検知用 19+ console.log('favorite>>',results); 20+ res.render('favorite.ejs',{user:username,tweets:results,title:"お気に入り"}); 21+ }); 22 }); 23 24- connection.query( 25- mysql2, 26- (error,results)=>{ 27- console.log('favorite>>',results); 28- res.render('favorite.ejs',{user:username,tweets:results,title:"お気に入り"}); 29- }); 30});//app.favorite

※エラーのキャッチアップ目的で、if (error) throw error;を挿入しています。
resultsundefinedになっている理由を探すという意味でも、
エラーが無いことが確認できる流れで通常処理に進んだほうが良いかと。

原因(仮説を含む

Node.jsのコールバック関数の処理が非同期で動きます。
そのため、最初のconnection.queryでメインのクエリ処理がされたあと、
指定したコールバック関数と2回目のconnection.queryのクエリ処理の
どちらが先に処理されるかがわかりません。

そのため、上記のようにコールバック内で処理をつなぐようにするか、
async/awaitなどのように処理順序をある程度担保出来る実装が必要になります。

※ここから先、自環境で不明瞭だった点

変数mysql2は当然ながら後続で組み立てることを前提にしているため、
初期段階ではSQLとしての構文は誤っています。(これ自体は正常)
そのため、近い環境を手元で用意して簡易的に試した範囲ではerrorの内容が、
構文エラーであるER_PARSE_ERRORとなっていました。

ただ、修正依頼欄で確認してもらったエラーはER_EMPTY_QUERYという、
空文字列でクエリ実行した時に出るエラーだったので、
そこの齟齬が起きた理由だけはちょっとわかっていません。

投稿2020/10/13 16:50

attakei

総合スコア2738

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

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

shibachi

2020/10/14 08:22

返信遅くなり申し訳ないです! たったいま確認したところ、きちんと表示されました!! console.log();の出力結果を見て、内容がおかしかったのでそこだけ修正しました。↓ -------------------------------------------------------------------------------------- app.get('/favorite', (req, res) => { var mysql1 = 'SELECT tweet_id FROM favorite WHERE user_id = ?'; var mysql2 = 'SELECT * FROM tweets WHERE id = '; connection.query( mysql1, [user_id], (error,results)=>{ if (error) throw error; console.log('user_id',user_id); console.log('results_id',results); mysql2 = mysql2 + results[0].tweet_id; for (var i = 1, len = results.length; i < len; ++i) { mysql2 = mysql2 + ' OR id = ' + results[i].tweet_id; }//for console.log('mysql2>>',mysql2); connection.query( mysql2, (error,results)=>{ if (error) throw error; // SQLエラー時の検知用 console.log('favorite>>',results); res.render('favorite.ejs',{user:username,tweets:results,title:"お気に入り"}); } ); } ); });//app.favorite
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問