🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
EJS

EJSは、JavaScript用のテンプレートエンジン。HTMLなどのテンプレートテキストにJavaScriptのロジックを記述することができます。また、変数・関数の実行をテンプレートテキスト内に埋め込むことも可能です。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Node.js

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

Q&A

0回答

325閲覧

Node.jsにて、PostgreSQLのデータを上手くEJSファイルに渡せません。

kanon_2155103

総合スコア7

EJS

EJSは、JavaScript用のテンプレートエンジン。HTMLなどのテンプレートテキストにJavaScriptのロジックを記述することができます。また、変数・関数の実行をテンプレートテキスト内に埋め込むことも可能です。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Node.js

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

0グッド

0クリップ

投稿2023/12/06 11:45

編集2023/12/07 09:47

前提

お世話になります。

node.jsで制作しているメモアプリで、現在MySQLからPostgreSQLへの移行を試みているのですが、そこで発生した問題についてお尋ねさせてください。
viewファイルにはEJSファイルを使用しております(EJSというのは、HTML内にJavascriptを簡単に記述できるJSのテンプレートエンジンです)。

先日投稿いたしました投稿( https://teratail.com/questions/6zqnuiwft1zlkp )の続きで、実行時に起こるエラーが変わりましたので、このたび質問を投稿し直すこととなりました。
見ていただかなくても今回の質問に差し障りはないと思いますが、以前発生していたエラーをご覧いただく際は、お手数ですが上記のページをご参照いただけますと幸いです。

メモアプリのルーティングについて簡単に説明しますと、/indexでメモの一覧情報を取得し/trashでゴミ箱に入れたメモの一覧ページを取得、また/newで新規メモの作成、/edit/:idで任意のメモの編集が行えるという感じです。

発生している問題

app.jsにて、PostgreSQLのテーブルデータをdata.rowsという形でEJSファイルに渡しているのですが、実際にアプリを実行すると次のような流れでエラーが発生します。

まず、アプリを実行して最初に'localhost:8001/index'、または'localhost:8001/trash'にアクセスすると、問題なくページを読み込むことができます。
しかし、そこから違うページを取得しようとすると、下記の出力結果における14行目以降のようなエラーが起こり、接続が途絶えてしまいます。

app.jsの出力結果

1Listeninng on 8001 // 1行目: アプリ実行時にconsole.infoで出力されるテキスト 2[ // 2~12行目: アプリを実行後、初めて/indexもしくは/trashにアクセスした際にconsole.logで出力されるdata.rowsの内容(/indexの場合) 3 { 4 id: 1, 5 title: 'hoge', 6 content: 'huga', 7 created: 2023-12-01T07:16:14.517Z, 8 modified: 2023-12-06T07:32:17.110Z, 9 is_removed: false, 10 is_locked: false, 11 modified_stamp: 'Dec 06 23 16:32' 12 } 13] 14C:\Users\Kanon\workspace\memo-app\app.js:79 // 14行目~: 最初にアクセスしたページから別のページに飛ぼうとすると起こるエラー 15 console.log(data.rows); 16 ^ 17 18TypeError: Cannot read properties of undefined (reading 'rows') 19 at Query.callback (C:\Users\Kanon\workspace\memo-app\app-new.js:79:21) 20 at Query.handleError (C:\Users\Kanon\workspace\memo-app\node_modules\pg\lib\query.js:128:19) 21 at C:\Users\Kanon\workspace\memo-app\node_modules\pg\lib\client.js:580:15 22 at processTicksAndRejections (node:internal/process/task_queues:78:11)

/indexに最初にアクセスするとそこから/trashにアクセスする際にエラーが起こり、/trashに最初にアクセスすると逆の結果になります。
/newにはいつでもアクセスできるのですが、新規メモのデータを保存しようとするとエラーが起こりました。
/edit/:idに至っては、最初のアクセスからエラーが起こり、常に取得ができない状態です。

なお、どのケースでも発生するエラーメッセージに変わりはありませんでした。

該当のソースコード・テーブル

こちらが該当のテーブル情報です。

PostgreSQLのmemosテーブル

1memo_app=# \d memos 2 テーブル"public.memos" 3 列 | タイプ | 照合順序 | Null 値を許容 | デフォルト 4----------------+-----------------------------+----------+---------------+------------------------------------------------------- 5 id | integer | | not null | nextval('memos_id_seq'::regclass) 6 title | character varying(40) | | | 'Untitled'::character varying 7 content | character varying(10485760) | | | 8 created | timestamp without time zone | | not null | CURRENT_TIMESTAMP 9 modified | timestamp without time zone | | not null | CURRENT_TIMESTAMP 10 is_removed | boolean | | not null | false 11 is_locked | boolean | | not null | false 12 modified_stamp | character varying(15) | | | generated always as (custom_to_char(modified)) stored 13インデックス: 14 "memos_pkey" PRIMARY KEY, btree (id) 15トリガー: 16 update_tri BEFORE UPDATE ON memos FOR EACH ROW EXECUTE FUNCTION set_update_time()

また、該当のJSファイル(app.jsとmodule.js)はこちらです。

app.js(周辺情報のみ)

1const express = require('express'); 2const mod = require('./module') 3const app = express(); 4 5app.use(express.static('public')); 6app.use(express.urlencoded({extended: false})); 7 8// Memo Listの取得 9app.get('/index', (req, res) => { 10 const connection = mod.connection; 11 connection.query( 12 'SELECT * FROM memos WHERE is_removed = false', 13 (err, data) => { 14 const result = data.rows; 15 console.log(result); 16 res.render('index.ejs', {memos: result}); 17 connection.end(); 18 } 19 ); 20}); 21 22// 新規メモの作成ページを表示 23app.get('/new', (req, res) => { 24 res.render('new.ejs'); 25}); 26 27// 新規メモを保存 28app.post('/create', (req, res) => { 29 const connection = mod.connection; 30 connection.query( 31 'INSERT INTO memos (title, content) VALUES (?, ?)', 32 [req.body.memoTitle, req.body.memoContent], 33 (err, data) => { 34 res.redirect('/index'); 35 connection.end(); 36 } 37 ); 38}); 39 40// メモの編集ページを取得 41app.get('/edit/:id', (req, res) => { 42 const connection = mod.connection; 43 connection.query( 44 'SELECT * FROM memos WHERE id = ?', 45 [req.params.id], 46 (err, data) => { 47 const result = data.rows; 48 res.render('edit.ejs', {memo: result[0]}); 49 connection.end(); 50 } 51 ); 52}); 53 54// メモを更新 55app.post('/update/:id', (req, res) => { 56 const connection = mod.connection; 57 connection.query( 58 'UPDATE memos SET title = ?, content= ? WHERE id = ?', 59 [req.body.memoTitle, req.body.memoContent, req.params.id], 60 (err, data) => { 61 res.redirect('/index'); 62 connection.end(); 63 } 64 ); 65}); 66 67// Trash Listの取得 68app.get('/trash', (req, res) => { 69 const connection = mod.connection; 70 connection.query( 71 'SELECT * FROM memos WHERE is_removed = true', 72 (err, data) => { 73 const result = data.rows; 74 console.log(result); 75 res.render('trash.ejs', {memos: result}); 76 connection.end(); 77 } 78 ); 79});

module.js(データベースの接続情報)

1const { Client } = require('pg'); 2 3const connection = new Client({ 4 user: 'postgres', 5 host: 'localhost', 6 database: 'hoge', 7 password: 'huga', 8 port: 5432, 9}); 10 11connection.connect(); 12 13module.exports = { 14 connection 15}

試したこと

エラー文を検索したところ、'TypeError: Cannot read properties of undefined (reading 'hoge')'というエラーはその値がundefinedの時に起こるという情報が見つかりました。
しかし、rows配列は存在しており、実際に一度目のアクセスでは取得が可能なため、解決に紐付けることはできませんでした。
参照したのは以下のページです。
https://magazine.techacademy.jp/magazine/26836

また、以下のような英語の記事をいくつか参照してみたのですが、今回の問題とは原因が少し異なるようでした(恥ずかしながら英語にあまり強くないため、正しく読み取れていない可能性は大いにあります)。
https://discourse.metabase.com/t/cannot-read-properties-of-undefined-reading-rows/18166
https://github.com/TanStack/table/issues/5098

他に、data.rowsを変数に代入してからEJSファイルに渡したりもしたのですが、特に関係はなかったようです。

追記(2023/12/07)

/edit:idのページの取得時にエラーが出る問題については、取得したテーブルデータを第二引数に指定する際のクエリ記法がMySQLとPostgresで異なっていることが原因でした。
/edit:id以外のルーティングでも使用していた記法ですので、全て以下のように修正することで問題なくデータを取得できるようになりました。

app.js(以下は/edit/:idのルーティングの例)

1// MySQLの記法 2app.get('/edit/:id', (req, res) => { 3 pool.query( 4 'SELECT * FROM memos WHERE id = $1', // '?'という書き方はPostgreSQLに対応していない 5 [req.params.id], 6 (error, results) => { 7 res.render('edit.ejs', {memo: results.rows[0]}); 8 } 9 ); 10}); 11 12// PostgreSQLの記法 13app.get('/edit/:id', (req, res) => { 14 pool.query( 15 'SELECT * FROM memos WHERE id = $1', // '?'の部分をPostgreSQLの記法に合わせ'$1'という書き方に変更 16 [req.params.id], 17 (error, results) => { 18 res.render('edit.ejs', {memo: results.rows[0]}); 19 } 20 ); 21});

参照したページは以下です。
https://qiita.com/sa9ra4ma/items/765660dfd6936aeaff1b

また、文字数の上限に達したため、今回の問題とは関係がなかったviewsファイルの情報を削除しました。

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

実行環境はWindows11です。

Node: v16.14.2
MySQL: v8.0.3
PostgreSQL: v16.1

他にご入用の情報があれば仰ってくださいませ。
知識が浅くて恐縮ですが、どうぞよろしくお願いいたします。

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

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

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

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

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

hoshi-takanori

2023/12/06 13:47

エラーメッセージを直訳すると data.rows における data が undefined ってことです。connection.query のコールバックには err と data の 2 つの引数がありますが、query でエラーが起きた場合は err にエラー内容が渡され、data は undefined になります。その辺に転がってるサンプルコードではエラー処理は省略されることが多いですが、現実のコードでは必ず err をチェックして、適切なエラーハンドリングを行う必要があります。 で、エラーの原因はたぶん connection.end() で接続を切った後に connection を使おうとしてることかと。そして、Web アプリでは基本的に生の connection ではなく、connection pool を使うべきでしょうね…。
kanon_2155103

2023/12/07 09:04

> hoshi-takanori様 前回に引き続き、ありがとうございます! connection poolを使用し、'pool.connect()'をスコープ外で宣言したところ、問題なく動作するようになりました! 変更点はこちら主に下記のふたつです。 // app.jsにて以下のコードを追加し、それに伴い不要になったコード(スコープ内のconnect()やend()など)を削除しました。 const port = process.env.PORT || 8001; pool.connect((err) => { if (err) { console.log('error connecting: ' + err.stack); return; } app.listen(port, () => { console.info(`Listeninng on ${port}`); }); }); // module.jsの内容を以下のように変更しました。 const { Pool } = require('pg'); const pool = new Pool({ user: 'postgres', host: 'localhost', database: 'memo_app', password: 'Wqttqpe1551krpl', port: 5432, }); module.exports = { pool }
kanon_2155103

2023/12/07 09:15 編集

また、/editアクセス時のエラーはクエリ内での引数の指定の仕方がMySQLとPostgreSQLで違うことが原因でした。詳しくは質問本文の追記欄に記載いたしますが、こちらについても解決できました。 ところで、ベストアンサーへのご指名についてはどうすればよいでしょうか? 私といたしましては、ぜひ回答の方に何らかの投稿をしていただけましたらと思うのですが、もしお望みでないようでしたらこのまま自己解決として処理いたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問