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

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

ただいまの
回答率

90.84%

  • JavaScript

    14838questions

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

  • Node.js

    1682questions

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

  • Oracle

    560questions

    Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。

NodeでのORACLEからのデータ取得

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 133

wolf2

score 4

現在NodeでORACLEからデータを取得する処理を実装しようとしているのですが、
下記のコードを試してもexecute内では値が取れるのですがデータを持ちまわる事が
出来ません。どうすれば持ちまわれますか?

var oracledb = require("oracledb");

module.exports = {
  Syain_Select: function (SYAIN_CD) {
    let sql = "select * from SYAIN_TB";
    let res = "";

    oracledb.getConnection(
      {
        connectString: "IP",
        user: "USER",
        password: "PASS",
      },
      function (err, conn) {
        if (err) {
          console.error(err.message);
          return;
        }
        conn.execute(sql, function (err, results, req) {
          res = results.rows[0];
          conn.close();
        });
      }
    );
    console.log(res);
  }
};
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

+1

Node.jsはノンブロッキングI/Oなので、非同期処理で取得した値を別の箇所で使用する場合はPromiseやasync/awaitを使いましょう。

Promise: https://qiita.com/toshihirock/items/e49b66f8685a8510bd76
async/await: https://qiita.com/Anders/items/dfcb48d8b27ceaffb443

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

データを持ちまわる事が出来ません。どうすれば持ちまわれますか?

基本的には出来ませんよ、
なので諦めてMr.ドリラーのように処理終了まで掘り続けてください。

でもまぁ、コールバック関数の使い方をしっかり覚えれば、
こんなに掘りまくらなくてもコールバック関数を要求する関数を上手く作ってハンドリング出来るので、Node.js力が身につけば自然と解決出来るでしょう。
Promiseやasync/awaitもその一環ですので、Node.jsを使い続けるならこれらの機能をちゃんと勉強して使いこなせるようにしてください。

これがベースです。


しかし、これが本筋じゃなさそうですね。
なのでちゃーんとデータを持ちまわる必殺技を覚える必要があるでしょう。
当然難解ですので、頑張って付いてきて下さいね。

代表的な手法は下記の2通りの組み合わせです。

  • 親スコープからオブジェクトや配列等を渡してやる
  • EventEmitterを覚える

このいずれか、または両方を組み合わせて実現させます。
EventEmitterは結構難解ですが、覚えなくても大丈夫です(理由は後述)

というわけで「親スコープからオブジェクトや配列等を渡してやる」を解説していきます。
まず、JavaScriptの変数の値はプリミティブ値オブジェクトかの二択です。
この内、オブジェクトはメモリ空間のアドレス値を使い、その実体はどこからでもアクセス出来るので、関数の引数や戻り値として別のものに手渡したとしても普通に中身にアクセスして読み書きが出来ます。

const user = {
  name: 'taro',
  age: 18
}
const main = he => {
  console.log(he.name) // taro
  he.sex = 'male'
  return he
}
const user2 = main(user)

console.log(user)  // {name: "taro", age: 18, sex: "male"}
console.log(user2) // {name: "taro", age: 18, sex: "male"}

このように、userは引数としてmain関数の中に突っ込んだだけなのに、
内部の関数でheを変更した余波がそのまま反映されましたね。
これを利用して値を取り出す事が出来ます。

この時、userの中身が数値や文字列等のプリミティブ値の場合は絶対に実現出来ませんし、
オブジェクトを渡したとしても関数の中でhe = {}のように代入をした場合、メモリ空間上の参照アドレス値が吹っ飛んで値が取り出せなくなりますので、
he.hoge = 123等のように、必ず内部のキー情報にアクセスしながら代入するようにしてください。

では、質問文のコードを軸にoracleから値を吸い出すロジックを考えていきましょう。
元々のコードはちょっと手直ししてこんな感じですかね。

// 仮にoracle.jsとする
const oracledb = require("oracledb");

module.exports = {
  // 引数にオブジェクトを要求する
  Syain_Select: function (state) {
    const {SYAIN_CD} = state; // 元々の引数予定だったSYAIN_CDはstate内へ引っ越し
    let sql = "select * from SYAIN_TB";
    let res = "";

    oracledb.getConnection(
      {
        connectString: "IP",
        user: "USER",
        password: "PASS",
      },
      function (err, conn) {
        if (err) {
          console.error(err.message);
          return;
        }
        conn.execute(sql, function (err, results, req) {
          res = results.rows[0];
          state.response = res; // ここでstateに保存!
          conn.close();
        });
      }
    );
  }
};

続いて使う側です。

const oracle = require('./oracle.js');
const state = {}; // 状態を意味するオブジェクトを宣言しておく

state.SYAIN_CD = '123456'; // 検索に利用するはずだった社員コードがstate内に引っ越したのでここに格納

oracle.Syain_Select(state); // 実行

// JSは非同期処理を実行すると了解といってすぐ戻ってくるのでresultにはアクセス出来ない
console.log(state); // {SYAIN_CD: '123456'}

// なので待つ
const wait = () => {
  console.log(state);
  if (state.result) return
  setTimeout(wait, 3000);
}

なんか微妙だなぁ…といった感じですが、この技法単体ではこんなもんです。
待てば結果が返って来て取得出来るだけなので御の字でしょう。
嫌ならコールバック関数で全部数珠つなぎにして頑張ってください。

次の章はEventEmitterと併用して使えない子からステップアップを目指します。


次にNode.jsを使って何を表現したいのでしょうか?
それによりアドバイスが変わります。

  • Expressを使ってWebサイトを構築したい
  • WebSocketを使ってWSサーバを構築したい

Node.jsを扱う動機で多いのは、このどちらかでしょう。
コイツらはEventEmitterの機能が搭載されているので、覚える必要がないと言ったのはそういう理由からです。
これらとは関係なく実現させたければ自分でEventEmitterを覚えて使いこなせるようにしてください。

今回はExpressとの併用を紹介しますので、WS目当てなら参考に頑張ってください。
まずは、サーバーを公開する前にDBにアクセスして置かなければならないモノを取得します。

const require('oracle.js');
const state = {};

const express = require('express');
const app = express();
app.get('/', (req, res) => {
  res.json(state.result);
})

// Webサーバは80番ポートで待ち受けなければ誰もアクセス出来ないので、結果が取れるまでせき止める
const wait = () => {
  if (!state.result) {
    return setTimeout(wait, 1000);
  }
  app.listener(80);
  console.log('get ready');
}

これでget readyがコンソール上に表示されてからアクセスすれば、
httpアクセスすると社員情報が返ってきます。


いや、社員コードは動的にアクセスしたいんだが

しょうがない、やっぱりコールバック関数に関するあたりの説明も必要ですね…
今回はNoderらしい方法でやっていきます。

まず、OracleのコネクションはWebサーバが毎回切断するのはアホです。
張りっぱなしが当然です。
なので関数を分けて張りっぱなしに出来るようstateオブジェクト内に保存し続ける作りにします。

各関数の引数にコールバック関数という引数を用意して要求するようにします。
この時、他のコールバック関数を引数に取る関数は、全て最終引数が該当するのでそれに合わせます。

// oracle2.js
const oracledb = require("oracledb");

module.exports = {
  getConn: function (cb) {
    oracledb.getConnection({
      connectString: "IP",
      user: "USER",
      password: "PASS",
    }, cb);
  },
  Syain_Select: function (conn, SYAIN_CD, cb) {
    // TODO: ここ入力値がそのままSQL文になってる可能性があるのでエスケープ作っておいてください
    let sql = `select * from SYAIN_TB where SYAIN_CB = '${SYAIN_CB}'`;
    conn.execute(sql, cb);
  }
};

こんな殺風景で大丈夫か?
これが最善です、結果を受け取った側が今後の動作を考えるべきなので、
こいつらがする事はシンプルな事にとどめましょう。

続いてExpressです。

const oracle = require('./oracle2.js');
const state = {}; // いつものやつ

const express = require('express');
const app = express();
app.get('/:code', (req, res) => {
  const code = req.params.code
  oracle.Syain_Select(state.conn, code, (err, results, req) => {
    if (err) {
      // 社員番号が取れなかったみたいな感じで
      res.status(400).json(err.message);
      return;
    }
    res.json(results.row);
  });
})

oracle.getConn((err, conn) => {
  if (err) throw err; // Oracleに接続出来なければサーバーは起動できない
  state.conn = conn; // getConnから持ち帰ってきたconnを保存
  app.listen(80); // サーバを起動
  console.log('get ready.');
})

ちょっと知恵の輪みたいに複雑でしたが、Node.jsではこのような流れで必要な値を適宜外のスコープに持ち帰りながらサーバを構築する必要があります。
ゆっくり読み返しながら反芻していってください。

処理が増えると長い直列の非同期処理が必要な事もあるかと思います。
どんどんネストが深くなっていきコードがカオスになっていきます。
ファイルを区切って抽象化したり、Promiseやasync/awaitの構文を覚えて管理出来るように学習してください。

それでは良きNode.jsライフを

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

0

callbackのみでDB操作は現実的ではありません。
node-oracledbはPromise化されているのでPromiseでがんばります。
https://oracle.github.io/node-oracledb/doc/api.html#promiseoverview

Promiseならばasync/await構文にもすぐに書き直せます。
上記URLのサンプルはこんな感じで書けます。
エラー処理はPromise.catchやtry-catchで挙動を確認しながら勉強してみてください。
突破口となれば幸いです。

const oracledb = require('oracledb');

(async ()=>{
    const conn = await oracledb.getConnection({
          user          : "hr",
          password      : "welcome",
          connectString : "localhost/XE"
        });
    const result = await conn.execute(
            `SELECT department_id, department_name
            FROM departments
            WHERE manager_id < :id`,
            [110]  // bind value for :id
        );
    console.log(result);
})()

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/13 19:44

    わざわざ自分が書き直さなくても↓にサンプルありますね^^
    https://oracle.github.io/node-oracledb/doc/api.html#asyncawaitoverview

    キャンセル

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

  • ただいまの回答率 90.84%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    14838questions

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

  • Node.js

    1682questions

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

  • Oracle

    560questions

    Oracleは、米オラクルが取り扱うリレーショナルデータベース管理システムです。メインフレームからPCまで、多様なプラットフォームに対応しています。