LoginSignup
Naoki23
@Naoki23 (早稲田 直輝)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

node.js, mySQLで同期処理をしたい

解決したいこと

データベースから取得したデータを処理したい。

発生している問題

ソースコードの一番下のconsole.logでqueryTextにデータが何も入っていない。

該当するソースコード

var queryText = [];
{
  connection.query(
    'SELECT problem_id FROM problem WHERE problem_id LIKE "%IT%" ORDER BY RAND() LIMIT 25',
    (error, results) => {
      var id = results;
      //console.log(id);
      for (var i = 0; i <= 24; i++) {
        var problemid = id[i];
        //console.log(problemid);
        connection.query(
          'SELECT * FROM problem WHERE problem_id = ?',
          [problemid.problem_id],
          (error, results) => {
            queryText.push(results[0].problem_text);
            //console.log(results[0].problem_text);
          }
        )
        connection.query(
          'SELECT * FROM choice WHERE problem_id = ?',
          [problemid.problem_id],
          (error, results) => {
            //console.log(results);
          }
        )
      }
    }
  );
}
console.log(queryText);

connection.queryが非同期処理なのは理解しました。
ですが、同期処理でデータベースからデータを取り出す方法が分かりません。

かなり行き詰まっているので助けてください。

1

3Answer

connection.queryはもしかして非同期実行ではないでしょうか?
なので、connection.queryが終わる前にconsole.logしてると思います。

1

Comments

  1. @Naoki23

    Questioner
    多分そうだと思うのですがデータベースからデータを取り出しながら同期処理はできないのでしょうか?
  2. 試してみてください

    ```js

    const util = require('util');
    connection.query = util.promisify(connection.query);

    var queryText = [];

    const results = await connection.query(
    'SELECT problem_id FROM problem WHERE problem_id LIKE "%IT%" ORDER BY RAND() LIMIT 25');

    var id = results;
    //console.log(id);

    for (var i = 0; i <= 24; i++) {
    var problemid = id[i];
    //console.log(problemid);

    const results2 = await connection.query('SELECT * FROM problem WHERE problem_id = ?', [problemid.problem_id]);
    queryText.push(results2[0].problem_text);
    //console.log(results2[0].problem_text);

    const results3 = await connection.query('SELECT * FROM choice WHERE problem_id = ?', [problemid.problem_id]);
    //console.log(results3);
    }

    console.log(queryText);

    ```

さっぱり理解していないのですが、Promiseを使えば、非同期処理の処理順を制御できるのではないでしょうか。

JavaScript Promiseの本
Qiitaで「Promise」を検索

追記

現状では結果に影響していないchoiceテーブルに対するクエリを無視すると、下記だけで要件を満たすように思われます。

var queryText = undefined;
connection.query(
  'SELECT problem_text FROM problem WHERE problem_id LIKE "%IT%" ORDER BY RAND() LIMIT 25',
  (error, results) => {
    queryText = result.map((item) => item.problem_text);
    console.log(queryText);
  }
);
1

Comments

  1. @Naoki23

    Questioner
    Promiseについて調べて軽く試してみたのですが、今のコードままだとconnection.queryの中にconnection.queryがあるのでどのように書けばいいのか分からないです。
  2. コードを見ていて感じたのですが、もしかして、javascriptで繰り返している部分も含めて、1回のクエリで全体を賄えるのではないでしょうか?
    未実装らしい、ループ中の2回目のクエリでの処理が、どのようなものであるかにもよると思いますが。
    もし、1回のクエリで賄えるのであれば、Promiseは必要ありませんね。
  3. コードを追記しました。
  4. 上手くお伝えできずに申し訳ございません。
    クエリでJOIN句を使うことで、`choice`テーブルからも情報を引き出すことができます。
    その場合でも、ほとんどの場合、一回のクエリで賄えると思います。
  5. @Naoki23

    Questioner
    返信ありがとうございます。それをしたとしても何かしらで同期処理はしないといけなかったので、一回のクエリでデータを取得しつつawaitで同期処理しようと思います。

Your answer might help someone💌