- 投稿日:2020-05-15T21:07:06+09:00
Vuetfiy v-dialogのモーダル化が機能しない
Vuetify v-dialogのモーダル化が機能しない
新規で作成もしくはソースコードの内容を大体把握してある個人の方・一人でプロジェクトを回している方には参考にならないかと思います。
Vuetifyの
v-dialog
にはオプションで色々指定できる
モーダル化させるためにpersistent
を指定することでダイアログ外を押しても閉じないようにできるそれが機能しなかったので備忘録的にまとめる
Vuetify
https://vuetifyjs.com/ja/components/dialogs/結論
outside
というオプションが悪さしていました。
このオプションはダイアログ外を押した時に発火するイベントです。
そいつが諸悪の権化なので削除するなりよしなに修正することで回避しましょう。こんなことで時間取られるの辛い…辛い…
ちなみに調べるとVuetify2.1以下だとバグで機能しないらしいですが、
orverlay
と合わせるとバグるみたいなので多分今回の場合は関係ないです。
https://github.com/vuetifyjs/vuetify/issues/8697
- 投稿日:2020-05-15T15:38:32+09:00
Kubernetes基礎(3):Overview
Kubernetes Overview
Kubernetes Cluster
サーバー1台はMasterとして使って、他の複数のサーバはNodeとしてMasterに接続します。
このような組み合わせで接続されているのをKubernetes Clusterと言います。
※Nodeは3つ以上を推薦しています。Master
Clusterを管理します。Node
リソースを提供します。
Cluster全体のリソースを増やしたい場合はNodeを追加します。
Nodeにはkubeletが存在し、Kubernetes Masterと通信(using kubernetes API)、Nodeを管理します。
(kubeletをagentとも呼びます。)Namespace
Cluster内のNamespaceがKubernetesのオブジェクトを独立した空間に分離(=隔離)します。
NamespaceはKubernetesの最小配布単位のPodがあり、このPodは外部からの接続が可能なように
IPアドレスを割り当てたServiceがあって接続が可能になります。
※別のNamespaceのPodへの接続はできない。Pod
PodはKubernetes Applicationの基本実行単位であり、Deployする最小単位です。
Podには複数のContainerが入れます。
Container毎に1つのApplicationが動作するため、Podは複数のApplicationの稼働ができます。Service
Kubernetesで動かしているサービス(PodのContainer)を外部公開します。
Podに含まれているContainerのtraffic load balancingをサポートします。Volume
Podに問題が生じて再生成されると、その中のデータは消えてしまいます。
Volumeを作成して繋げておけば、データはVolumeに保管されるのでPodが再生成されても、データは消えません。ResourceQuota/LimitRange
1つのNamespaceで使えるリソースの制御ができます。
例)Pod数、CPU、MemoryConfigMap/Secret
Podの作成時、Containerの環境変数などを設定したファイルへのMountができます。Controller
Podを管理する。
・Replication Controller/ ReplicaSet(基本的なController)
Podの状況を常に監視し、Podが多すぎるとPodを除去し、少ないとPodを開始したり、Podを管理します。
・Deployment
Application Instanceの生成と更新を担当します。
Podのバージョン管理を行います。
アップグレード時、問題が発生した場合はロールバックもできます。
・DaemonSet
1つのNodeに1つのPodが維持出来るように管理します。
・Job
1つ以上のPodを作成し、指定された数のPodが正常に終了することを保証します。
このJobを定期的に実行するときはCronJobを使います。
- 投稿日:2020-05-15T15:21:35+09:00
webpack 4系でwebpack.config.jsの自動生成ができないときの解決方法
株式会社ONE WEDGEでエンジニアをしている @YoukeyMurakami です。
プロジェクト開始時、今までwebpack.config.jsは手でシコシコ書いていたんですけど、「自動生成出来るよ」って聞いたので試してみたときの備忘録になります。
環境
結果的にOKだった環境は次の通り
name version node.js 13.8.0 webpack 4.43.0 webpack-cli 3.31.0 @webpack-cli/init 0.2.2 失敗したケース
# 各種ツール類のインストール $ yarn add -D webpack webpack-cli @webpack-cli/init # webpack.config.jsの自動生成 $ webpack init /Users/YoukyMurakami/project_hoge/node_modules/@webpack-cli/utils/npm-packages-exists.js:42 throw new TypeError(chalk_1.default.bold(`${scaffold} isn't a valid name.\n`) + ^ TypeError: init isn't a valid name. It should be prefixed with 'webpack-scaffold', but have different suffix. at /Users/YoukyMurakami/project_hoge/node_modules/@webpack-cli/utils/npm-packages-exists.js:42:19 at Array.forEach (<anonymous>) at Object.npmPackagesExists [as default] (/Users/YoukyMurakami/project_hoge/node_modules/@webpack-cli/utils/npm-packages-exists.js:26:9) at initializeInquirer (/Users/YoukyMurakami/project_hoge/node_modules/@webpack-cli/init/index.js:23:41) at runWhenInstalled (/Users/YoukyMurakami/project_hoge/node_modules/webpack-cli/bin/utils/prompt-command.js:46:9) at promptForInstallation (/Users/YoukyMurakami/project_hoge/node_modules/webpack-cli/bin/utils/prompt-command.js:140:10) at /Users/YoukyMurakami/project_hoge/node_modules/webpack-cli/bin/cli.js:32:43 at Object.<anonymous> (/Users/YoukyMurakami/project_hoge/node_modules/webpack-cli/bin/cli.js:366:3) at Module._compile (internal/modules/cjs/loader.js:1151:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1171:10)oh...
TypeError: init isn't a valid name.
って出ていますね。
ちょっとググってみると、どうやらinitじゃなくてcreateになるよってことらしいのですが、createを使うにはwebpack-cli@beta
をインストールしてねということだそうです。
webpack-cli本体のバージョンは上げずになんとかするには・・・解決策
webpack-cliとwebpackのバージョンの組み合わせによりうまく動かないようなので、以下のコマンドでダウングレードしたwebpack-cliをインストールして下さい。
# 0.2.2バージョン指定でインストール $ yarn add -D webpack webpack-cli@0.2.2$ webpack init INFO For more information and a detailed description of each question, have a look at: https://github.com/webpack/webpack-cli/blob/master/INIT.md INFO Alternatively, run "webpack(-cli) --help" for usage info ? Will your application have multiple bundles? (y/N) Run-async wrapped function (sync) returned a promise but async() callback must be executed to resolve.無事に動きました!
最終的なpackage.jsonを貼っておきます。package.json{ "name": "hoge", "description": "hogehoge", "version": "0.0.1", "private": true, "dependencies": { }, "devDependencies": { "webpack": "^4.43.0" "@webpack-cli/init": "0.2.2", }, "scripts": { "test": "jest" } }仲間募集!
株式会社ONE WEDGEでは元気なエンジニア募集中です!一緒に「おもしろい」を作りましょう!
- 投稿日:2020-05-15T12:27:04+09:00
爆速構築!json-serverでMock API
はじめに
フロントエンド開発のためにAPIのモックが必要になったので、json-serverを利用してモックサーバを構築していきます。
基本的な環境構築
初期化
powershell# プロジェクトディレクトリを作成し, 移動する mkdir mock-api cd ./mock-api # 初期化処理 npm init -yjson-server
今回のメインとなる json-server を導入します。
powershellnpm i -D json-servercontents.json
エンドポイントとなる json ファイルを作成します。
powershellmkdir api new-item api/contents.json作成した contents.json を編集します。
ここで編集した内容がAPIのレスポンスとして返されるようになります。contents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ] }package.json
package.json を更新します。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから追加 ↓↓↓↓↓ ### "json-server": "json-server --watch ./api/contents.json --port 5000" ### ↑↑↑↑↑ ここまで追加 ↑↑↑↑↑ ### }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }実行
npm run
コマンドで実行します。powershellnpm run json-server実行されると、以下にGET通信することで先ほどのcontents.jsonの内容が得られます。
http://localhost:5000/contents応用的な環境構築
エンドポイントを複数用意したい場合
エンドポイントを複数用意したい場合、contents.jsonにもう一つ要素を追加することで解決します。
contents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ], "authors": [ { "id": 1, "name": "hoge" }, { "id": 2, "name": "fuga" } ] }上記のように編集し実行すると、以下のように通信先を切り替えることができます。
http://localhost:5000/contents http://localhost:5000/authorsエンドポイント毎にファイルを分割したい場合
しかし、APIの規模が大きくなってくると単一ファイルではメンテナンスが難しくなってくることは想像に難しくありません。
そうなると「エンドポイント毎にファイルを分割したい」という欲求が生まれてきます。そこで問題となってくるのが json-server の「単一ファイルしか受け付けない」という仕様です。
なので、今回は複数ファイルを一つにマージすることで対応したいと思います。【参考】
- Json-serverでモックAPI(1) まず、マージをするためのスクリプトを用意します
powershellmkdir scripts new-item merge.jsscripts/merge.jsconst path = require("path"); const fs = require("fs"); const root = path.resolve("./", "api"); const update = () => { const api = fs.readdirSync(root).reduce((api, file) => { if (api === undefined) api = {}; if (path.extname(file) == ".json") { const endpoint = path.basename(file, path.extname(file)); if (api[endpoint] === undefined) api[endpoint] = {}; api[endpoint] = JSON.parse(fs.readFileSync(root + "/" + file, "utf-8")); return api; } }, {}); fs.writeFile(root + "/../merged.json", JSON.stringify(api), err => { if (err) throw err; }); } // 初回作成 update(); // jsonファイルを監視し, 監視ファイルに更新があるたびmerged.jsonを更新 fs.watch(root, (e, filename) => update());(2) json-server と merge.js を両方同時に動作させるために npm-run-all を導入します
powershellnpm i -D npm-run-all(3) package.json を更新します
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから追加・更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000", "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" ### ↑↑↑↑↑ ここまで追加・更新 ↑↑↑↑↑ ### }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }(4) contents.json を contents.json と authors.json に分割します
powershellnew-item api/authors.jsoncontents.json{ "contents": [ { "id": 1, "title": "title - foo", "body": "body - bar", "author-id": 1 }, { "id": 2, "title": "title - foo2", "body": "body - bar", "author-id": 1 }, { "id": 3, "title": "title - bar", "body": "body - bal", "author-id": 2 } ] }authors.json{ "authors": [ { "id": 1, "name": "hoge" }, { "id": 2, "name": "fuga" } ] }(5) 以下のコマンドで実行します
powershellnpm run serveこれで複数ファイルに分割定義することが可能となります。
POSTやPUTでもレスポンスを受け取りたい場合
json-server は GET以外 のリクエストだと思ったようにレスポンスを返してくれないので、処理をフックして GET通信 に偽装します。
【参考】
- json-server で使い捨てモックサーバを作る
- JSON Serverを使ってGETとPOSTでレスポンスを変えてみた(1) まず、処理をフックするためのスクリプトを追加します
powershellnew-item ./scripts/middleware.jsmiddleware.jsmodule.exports = (req, res, next) => { if(req.method == 'POST') { req.method = 'GET' // GETに偽装 req.query = req.body } next() }(2) package.json を更新します
以下では、--middlewares オプションを追加しています。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000 --middlewares ./scripts/middleware.js", ### ↑↑↑↑↑ ここまで更新 ↑↑↑↑↑ ### "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }これでPOST通信でもjsonレスポンスを得ることができます。
APIのrouteをカスタムしたい場合
現状、APIのrouteが http://localhost:5000/{jsonファイル名} となっているため、これを http://localhost:5000/api/v1/{jsonファイル名} となるように変更してみたいと思います。
【参考】
- Json-serverでモックAPI(1) まず、routes.json を追加します
powershellnew-item ./routes.jsonroutes.json{ "/api/v1/*": "/$1" }(2) package.json を更新します
以下では、--routes オプションを追加しています。
package.json{ "name": "mock-api", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", ### ↓↓↓↓↓ ここから更新 ↓↓↓↓↓ ### "json-server": "json-server --watch merged.json --port 5000 --routes ./routes.json --middlewares ./scripts/middleware.js", ### ↑↑↑↑↑ ここまで更新 ↑↑↑↑↑ ### "merge": "node ./scripts/merge.js", "serve": "npm-run-all -p merge json-server" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "json-server": "^0.16.1" } }これでhttp://localhost:5000/api/v1/{jsonファイル名}でアクセスできるようになります。
おわりに
さらに詳しくは 公式サイト をご参照ください。
- 投稿日:2020-05-15T12:21:24+09:00
Bitriseのステータスをモニターに表示して物理的に監視する
背景
- Bitriseのワークフローが成功/失敗したらSlackに通知する仕組みはよくある
- 物理的にモニターにステータスを表示するツールの紹介はあまり見ない
ツール
https://github.com/marcells/node-build-monitor
こんな感じで表示される
https://builds.mspi.es/ にデモがあるので見てみてください。
表示形式の変更や、失敗したら音を鳴らすなどの設定も可能です。やってみる
GitHubのREADMEで詳細は記載されているので、ここではBitriseを使用したハッピーパスだけ紹介します。
- リポジトリを任意のディレクトリへClone
- https://github.com/marcells/node-build-monitor#bitrise にあるように、
app/config.json
を以下のように記述{ "monitor": { "interval": 300000, "numberOfBuilds": 12, "latestBuildOnly": false, "sortOrder": "date", "debug": false }, "services": [ { "name": "Bitrise", "configuration": { "slug": "BitriseでのアプリID", "token": "パーソナルアクセストークン" } } ] }
- Nodeでローカル実行(https://github.com/marcells/node-build-monitor#run-it-manually-during-development)
- Dockerで実行(https://github.com/marcells/node-build-monitor#run-it-with-docker-compose-in-production)
最後に
Slackの通知でも気づくことはもちろんできますが、オフィスのサイネージなどで表示しておけばエンジニアだけでなく、PMやデザイナーなどのプロジェクトメンバー全員がCIのステータスを気にする意識が持てるので、そこから何かいいアクションに繋がればいいなと思います。
- 投稿日:2020-05-15T12:21:24+09:00
Bitriseのステータスをモニターに表示して物理的に監視するツールの紹介
背景
- Bitriseのワークフローが成功/失敗したらSlackに通知する仕組みはよくある
- 物理的にモニターにステータスを表示するツールの紹介はあまり見ない
- 複数のCIサービスのステータスを1画面でみたい
ツール
https://github.com/marcells/node-build-monitor
こんな感じで表示される
https://builds.mspi.es/ にデモがあるので見てみてください。
表示形式の変更や、失敗したら音を鳴らすなどの設定も可能です。やってみる
GitHubのREADMEで詳細は記載されているので、ここではBitriseを使用したハッピーパスだけ紹介します。
- リポジトリを任意のディレクトリへClone
- https://github.com/marcells/node-build-monitor#bitrise にあるように、
app/config.json
を以下のように記述{ "monitor": { "interval": 300000, "numberOfBuilds": 12, "latestBuildOnly": false, "sortOrder": "date", "debug": false }, "services": [ { "name": "Bitrise", "configuration": { "slug": "BitriseでのアプリID", "token": "パーソナルアクセストークン" } } ] }
- アプリIDはURLの
app
以降の文字列Nodeでローカル実行(https://github.com/marcells/node-build-monitor#run-it-manually-during-development)
Dockerで実行(https://github.com/marcells/node-build-monitor#run-it-with-docker-compose-in-production)
最後に
Slackの通知でも気づくことはもちろんできますが、オフィスのサイネージなどで表示しておけばエンジニアだけでなく、PMやデザイナーなどのプロジェクトメンバー全員がCIのステータスを気にする意識が持てるので、そこから何かいいアクションに繋がればいいなと思います。
- 投稿日:2020-05-15T10:42:34+09:00
耳年齢判定ボットを改良(LINEで音声ファイルを再生)
概要
普段は耳鼻科の開業医をしています。
以前obnizeのスピーカーからモスキート音を出し加齢性難聴をチェックするLINE Botを作成しました。
耳年齢を判定するLINE Bot×Iotの作成今回、モスキート音をファイルに入れ、LINEで音声ファイルを再生できるようにしました。
作成方法
1.モスキート音を用意する
こちらを利用しました
Sine Tone Generator『File Generator』の
『Hz』をモスキート音の周波数に設定、『duration』は3秒とし『DOWNROAD.WAV FILE』をクリックするとダウンロードできます。
各周波数分用意します。2.publicフォルダを作ってwavファイルを設置
3.コードの追加
const config = { channelSecret: process.env.CHANNEL_SECRET, channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN }; const app = express(); app.use(express.static('public')); //追加3.wavファイルのURLを動的に取得する
app.post('/webhook'......内の処理を書き換えるPromise .all(req.body.events.map(event=>handleEvent(event,req))) .then((result) => res.json(result));function handleEvent(event) { に引数を追加
function handleEvent(event, req) { console.log(req); if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); }メッセージ内にURLを入れる
let url; if (hz == 0) { url =""; } else if (hz == 8000) { url ="デプロイしたボットのURL/public/8000.wav"; } else if (hz == 10000) { url ="デプロイしたボットのURL/10000.wav"; } else if (hz == 12000) { url ="デプロイしたボットのURL/12000.wav"; } else if (hz == 14000) { url ="デプロイしたボットのURL/14000.wav"; } else if (hz == 15000) { url ="デプロイしたボットのURL/15000.wav"; } else if (hz == 16000) { url ="デプロイしたボットのURL/16000.wav"; }LINEで複数のメッセージを返信する
replyMessage(event.replyToken, [ { type: "text", text: "第一のメッセージ" }, { type: "text", text: '第二のメッセージ' } ])完成
- 投稿日:2020-05-15T01:25:06+09:00
Windows上でSQL Serverを使用してNode.jsアプリを作成する
はじめに
この記事では、Microsoft 社が公開している Build an app using SQL Server の内容に従い、SQL Server を使用した Node.js アプリを作成します。
第30回 SQL Server 2019 勉強会@JSSUG (2020/5/16) のセッション資料です。
環境
- OS: Windows 10 Pro 10.0.19041 N/A ビルド 19041
- SQL Server: SQL Server 2019
- Node.js: v12.16.1
環境のセットアップ
SQL Server のインストール
ウェブ上では、ホスト OS に SQL Server 2017 Developer 以上をインストール とあります。
[こちら][SQLServerDownload] のサイトより、SQL Server 2019 Developer インストーラーをダウンロードし、インストールを行ってください。筆者は、WSL2 (Ubuntu 18.04 LTS) 上にインストールした Docker 上に、
SQL Server 2019 on Linux
をインストールして利用しました。docker-compose.yaml については、以下の GitHub リポジトリを参考にしてください。構築後、ifconfig コマンドを実行し、eth0 の IP アドレスを確認してください。Chocolatey と Node.js のインストール
既に Node.js をインストール済みの場合は、スキップして問題ありません。まだ Node.js をインストールしていない場合は、インストールを行ってください。
サイトでは、Chocolatey を使った Node.js のインストールについて説明されています。Chocolatory とは、Windows 版パッケージ管理マネージャーです。Ubuntu でいう apt-get、RHEL/CentOS でいう yum に相当します。なお、筆者は docker 上に作成した Node.js コンテナを使用しました。先ほど作成した SQL Server on Linux コンテナと Node.js コンテナ同士が接続できるようにネットワーク設定を行えば、以降の作業を Docker 上で行うことも可能です。
Chocolateyをインストール@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"ChocolateyでNode.jsをインストールchoco install -y nodejs
SQLCMD のインストール
SQLCMD は、SQL Server に接続してクエリを実行できるコマンドラインツールです。まだインストールしていない場合は、以下の手順に従ってインストールを行ってください。
- ODBC Driver for SQL Server をダウンロードし、インストール
- sqlcmd ユーティリティ をダウンロードし、インストール
インストールが完了したら、SQLCMD を利用して SQL Server に接続できることを確認します。
sqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -Q "SELECT @@VERSION"SQL Server を使った Node.js アプリケーションを作成
ここでは、以下、2 つのシンプルな Node.js アプリを作成します。
- 基本的な Insert、Update、Delete、Select を実行するアプリ
- Node.js の ORM の中でも特に人気のある Sequelize を利用してInsert、Update、Delete、Select を実行するアプリ
SQL Server に接続してクエリを実行する Node.js アプリを作成
まずはじめに、Node.js プロジェクトを初期化します。
# 作業を行うフォルダに移動 cd ~/ # アプリ用のフォルダを作成 mkdir SqlServerSample cd SqlServerSample # npm パッケージをセットアップ npm init -y # プロジェクトフォルダに tedious と async モジュールをインストール npm install tedious npm install asyncプロジェクトの初期化が完了したら、sqlcmd を使用してSQL Serverに接続します。
以下のステートメントを実行して、今回使用するデータベースを作成します。sqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -Q "CREATE DATABASE SampleDB;"準備ができたところで、アプリを作成していきます。
お気に入りのエディタを使って、SqlServerSample フォルダ内に connect.js というファイルを作成します。
ユーザー名とパスワードは自分のものに置き換えることを忘れないでください。
なお、筆者は、Visual Studio Code を利用しています。connect.jsvar Connection = require('tedious').Connection; var Request = require('tedious').Request; var TYPES = require('tedious').TYPES; // データベースへのコネクション情報を作成 var config = { server: 'localhost', // 接続先の SQL Server インスタンス authentication: { type: 'default', options: { userName: 'sa', // 接続ユーザー名 password: 'your_password' // 接続パスワード } }, options: { database: 'SampleDB' // 接続するデータベース(ここは変えないでください) } } var connection = new Connection(config); // コネクション情報を使用して、接続とクエリ実行 connection.on('connect', function(err) { if (err) { console.log(err); } else { console.log('接続されました。'); } });実際に connect.js を動かします。
node connect.js
次に、SqlServerSample フォルダ内に CreateTestData.sql というファイルを作成します。
このファイルでは、T-SQL を使用して、SampleDB 内にスキーマおよびテーブルが作成を作成し、データを登録します。CreateTestData.sqlCREATE SCHEMA TestSchema; GO CREATE TABLE TestSchema.Employees ( Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY, Name NVARCHAR(50), Location NVARCHAR(50) ); GO INSERT INTO TestSchema.Employees (Name, Location) VALUES (N'Jared', N'Australia'), (N'Nikita', N'India'), (N'Tom', N'Germany'); GO SELECT * FROM TestSchema.Employees; GOSQLCMD を使って CreateTestData.sql を実行します。
sqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -d SampleDB -i ./CreateTestData.sqlSqlServerSample フォルダ内に crud.js という新しいファイルを作成します。
Insert、Update、Delete、Select を行う処理を記載していきます。
ユーザー名とパスワードは自分のものに置き換えることを忘れないでください。
crud.jsvar Connection = require('tedious').Connection; var Request = require('tedious').Request; var TYPES = require('tedious').TYPES; var async = require('async'); // データベースへのコネクション情報を作成 var config = { server: 'localhost', // 接続先の SQL Server インスタンス authentication: { type: 'default', options: { userName: 'sa', // 接続ユーザー名 password: 'your_password' // 接続パスワード } }, options: { database: 'SampleDB' // 接続するデータベース(ここは変えないでください) } } var connection = new Connection(config); function Start(callback) { console.log('開始しています...'); callback(null, 'Jake', 'United States'); } function Insert(name, location, callback) { console.log("テーブルに '" + name + "' を追加しています..."); request = new Request( 'INSERT INTO TestSchema.Employees (Name, Location) OUTPUT INSERTED.Id VALUES (@Name, @Location);', function(err, rowCount, rows) { if (err) { callback(err); } else { console.log(rowCount + ' 行 追加されました。'); callback(null, 'Nikita', 'United States'); } }); request.addParameter('Name', TYPES.NVarChar, name); request.addParameter('Location', TYPES.NVarChar, location); // SQL ステートメントを実行 connection.execSql(request); } function Update(name, location, callback) { console.log("Location '" + location + "' の name '" + name + "' を更新しています..."); // 依頼された従業員の記録を更新 request = new Request( 'UPDATE TestSchema.Employees SET Location=@Location WHERE Name = @Name;', function(err, rowCount, rows) { if (err) { callback(err); } else { console.log(rowCount + ' 行 更新されました。'); callback(null, 'Jared'); } }); request.addParameter('Name', TYPES.NVarChar, name); request.addParameter('Location', TYPES.NVarChar, location); // SQL ステートメントを実行 connection.execSql(request); } function Delete(name, callback) { console.log("テーブルから '" + name + "' を削除しています..."); // 要求された従業員の記録を削除 request = new Request( 'DELETE FROM TestSchema.Employees WHERE Name = @Name;', function(err, rowCount, rows) { if (err) { callback(err); } else { console.log(rowCount + ' 行 削除しました。'); callback(null); } }); request.addParameter('Name', TYPES.NVarChar, name); // SQL ステートメントを実行 connection.execSql(request); } function Read(callback) { console.log('テーブルの行データを読み取っています...'); // テーブルからすべての行を読み込む request = new Request( 'SELECT Id, Name, Location FROM TestSchema.Employees;', function(err, rowCount, rows) { if (err) { callback(err); } else { console.log(rowCount + ' 行 読み込みました。'); callback(null); } }); // 読み込んだ行データの表示 var result = ""; request.on('row', function(columns) { columns.forEach(function(column) { if (column.value === null) { console.log('NULL'); } else { result += column.value + " "; } }); console.log(result); result = ""; }); // SQL ステートメントを実行 connection.execSql(request); } function Complete(err, result) { if (err) { callback(err); } else { console.log("完了しました!"); } } // コネクション情報を使用して、接続とクエリ実行 connection.on('connect', function(err) { if (err) { console.log(err); } else { console.log('接続されました。'); // 配列内の全ての関数を連続的に実行 async.waterfall([ Start, Insert, Update, Delete, Read ], Complete) } });実際に、crud.js を動かします。
node crud.js
Sequelize ORM を使って SQL Server に接続する Node.js アプリを作成
アプリのフォルダを作成し、Node の依存関係を初期化します。
# 作業を行うフォルダに移動 cd ~/ # アプリ用のフォルダを作成 mkdir SqlServerSequelizeSample cd SqlServerSequelizeSample # npm パッケージをセットアップ npm init -y # プロジェクトフォルダに tedious と sequelize モジュールをインストール npm install tedious npm install sequelizeSqlServerSequelizeSample フォルダ内に orm.js という新しいファイルを作成します。
パスワードは自分のものに置き換えることを忘れないでください。
orm.jsvar Sequelize = require('sequelize'); var userName = 'sa'; // 接続ユーザー名 var password = 'your_password'; // 接続パスワード var hostName = 'localhost'; // 接続先の SQL Server インスタンス var sampleDbName = 'SampleDB'; // 接続するデータベース(ここは変えないでください) // Sequelize を初期化して SampleDB に接続 var sampleDb = new Sequelize(sampleDbName, userName, password, { dialect: 'mssql', host: hostName, port: 1433, // 接続ポート番号 logging: false, // ロギングを無効化(デフォルトは console.log) dialectOptions: { requestTimeout: 30000 // タイムアウトは 30 秒 } }); // 'User' モデルを定義 var User = sampleDb.define('user', { firstName: Sequelize.STRING, lastName: Sequelize.STRING }); // 'Task' モデルを定義 var Task = sampleDb.define('task', { title: Sequelize.STRING, dueDate: Sequelize.DATE, isComplete: Sequelize.BOOLEAN }); // User と Task は 1:N の関係 User.hasMany(Task); console.log('**Sequelize と MSSQL を使った Node CRUD のサンプル**'); // データベース内のテーブルとリレーションシップを DROP および CREATE するよう Sequelize に指示 sampleDb.sync({force: true}) .then(function() { console.log('\nモデルからデータベーススキーマを作成.'); // Create デモ: ユーザーインスタンスを作成し、データベースに保存 User.create({firstName: 'Anna', lastName: 'Shrestinian'}) .then(function(user) { console.log('\n作成されたユーザー:', user.get({ plain: true})); // Create デモ: タスクインスタンスを作成し、データベースに保存 Task.create({ title: 'Ship Helsinki', dueDate: new Date(2017,04,01), isComplete: false }) .then(function(task) { console.log('\n作成されたタスク:', task.get({ plain: true})); // Association デモ: ユーザーにタスクを割り当てる user.setTasks([task]) .then(function() { console.log('\n割り当てられたタスク \'' + task.title + '\' to user ' + user.firstName + ' ' + user.lastName); // Read デモ: ユーザー 'Anna' に割り当てられた未完了のタスクを見つける User.findAll({ where: { firstName: 'Anna'}, include: [{ model: Task, where: { isComplete: false } }] }) .then(function(users) { console.log('\nAnna に割り当てられた未完了のタスク:\n', JSON.stringify(users)); // Update デモ: タスクの 'dueDate' を変更 Task.findById(1).then(function(task) { console.log('\n更新中のタスク:', task.title + ' ' + task.dueDate); task.update({ dueDate: new Date(2016,06,30) }) .then(function() { console.log('期限が変更されました。:', task.title + ' ' + task.dueDate); // Delete デモ: dueDate が 2016年 であるすべてのタスクを削除 console.log('\n期限が2016年になっているタスクをすべて削除しています。'); Task.destroy({ where: { dueDate: {$lte: new Date(2016,12,31)}} }) .then(function() { Task.findAll() .then(function(tasks) { console.log('削除後のデータベース内のタスク一覧:', JSON.stringify(tasks)); console.log('\nすべて完了しました!'); }) }) }) }) }) }) }) }) })実際に、orm.js を動かします。
node orm.js
これで、2つ目の Node.js アプリの作成が終わりました。最後に、SQL Server の Columnstore 機能を使って Node.js アプリを高速化する方法について学びます。
Node.js アプリを 100 倍速にする
これまでで基本的なことは理解できたと思います。最後は、SQL Server を使用してアプリをより良くする方法を見てみます。このモジュールでは、Columnstore Index の簡単な例と、Columnstore Index がどのようにデータ処理速度を向上させるかを確認します。Columnstore インデックスは、従来の rowstore インデックスに比べて、分析ワークロードでは最大 100 倍のパフォーマンス向上、データ圧縮では最大 10 倍のパフォーマンス向上を実現できます。
SQLCMD を使用して 500 万のデータを含む新しいテーブルを作成
アプリのフォルダを作成します。
# 作業を行うフォルダに移動 cd ~/ # アプリ用のフォルダを作成 mkdir SqlServerColumnstoreSample cd SqlServerColumnstoreSampleSqlServerColumnstoreSample フォルダ内に CreateSampleTable.sql という名前の新しいファイルを作成します。
CreateSampleTable.sqlsqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -d SampleDB -t 60000 -Q "WITH a AS (SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) AS a(a)) SELECT TOP(5000000) ROW_NUMBER() OVER (ORDER BY a.a) AS OrderItemId ,a.a + b.a + c.a + d.a + e.a + f.a + g.a + h.a AS OrderId ,a.a * 10 AS Price ,CONCAT(a.a, N' ', b.a, N' ', c.a, N' ', d.a, N' ', e.a, N' ', f.a, N' ', g.a, N' ', h.a) AS ProductName INTO Table_with_5M_rows FROM a, a AS b, a AS c, a AS d, a AS e, a AS f, a AS g, a AS h;"sqlcmd を使ってデータベースに接続し、SQL スクリプトを実行して 500 万行データを持つテーブルを作成します。これは実行に数分かかるかもしれません。
sqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -d SampleDB -i ./CreateSampleTable.sqlテーブルをクエリして時間を測定する Node.js アプリを作成
プロジェクトフォルダ内で、Node.js の依存関係を初期化します。
# npm パッケージをセットアップ npm init -y # プロジェクトフォルダに tedious と async モジュールをインストール npm install tedious npm install node-uuid npm install asyncSqlServerColumnstoreSample フォルダ内に columnstore.js というファイルを作成します。
パスワードは自分のものに置き換えることを忘れないでください。
columnstore.jsvar Connection = require('tedious').Connection; var Request = require('tedious').Request; var uuid = require('node-uuid'); var async = require('async'); var config = { server: 'localhost', // 接続先の SQL Server インスタンス authentication: { type: 'default', options: { userName: 'sa', // 接続ユーザー名 password: 'your_password' // 接続パスワード } }, options: { database: 'SampleDB' // 接続するデータベース(ここは変えないでください) } // Azure SQL Databaseに接続するときは、次のオプションが必要 //options: {encrypt: true, database: 'yourDatabase'} }; var connection = new Connection(config); function exec(sql) { var timerName = "QueryTime"; var request = new Request(sql, function(err) { if (err) { console.log(err); } }); request.on('doneProc', function(rowCount, more, rows) { if(!more){ console.timeEnd(timerName); } }); request.on('row', function(columns) { columns.forEach(function(column) { console.log("Sum: " + column.value); }); }); console.time(timerName); connection.execSql(request); } // 接続を開き、クエリを実行 connection.on('connect', function(err) { async.waterfall([ function(){ exec('SELECT SUM(Price) FROM Table_with_5M_rows'); }, ]); });クエリ実行にかかる時間を測定
アプリを実行し、時間を計測します。
node columnstore.jsテーブルにカラムストアインデックスを追加
SQLCMD を実行して、カラムストアインデックスを追加します。
sqlcmd -S <接続するSQL Serverインスタンス名> -U sa -P <saユーザーパスワード> -d SampleDB -Q "CREATE CLUSTERED COLUMNSTORE INDEX Columnstoreindex ON Table_with_5M_rows;"columnstore.js スクリプトを再実行して今回のクエリが完了するまでにかかった時間に注目
node columnstore.jsおめでとうございます。カラムストアインデックスを使って Node.js アプリを高速化しました!
おわりに
以上で、「Windows上でSQL Serverを使用してNode.jsアプリを作成する」は終了です。Build an app using SQL Server には、他言語での SQL Server アプリを作成するチュートリアルがあります。ぜひ、他の言語でも試してみてください。
- 投稿日:2020-05-15T00:36:30+09:00
Node.jsに変わるかも?と言われている、Deno 1.0がリリースされたので素振りしてみた。
Deno1.0がリリースされたことで、twitterで界隈で話題になっていたので、素振りしてみた。(メモ程度です)
詳細は公式サイトをご確認ください。
https://deno.land/まずは、インストール
brew install denoこれで準備はOK!まずは、「Getting Started」をやってみた。
実行コマンド: deno run (ファイル名)
deno run https://deno.land/std/examples/welcome.ts // => Welcome to Deno ?
http://localhost:8000/にアクセスすると、「Hello World」が表示される。
hello_http.tsimport { serve } from "https://deno.land/std@0.50.0/http/server.ts"; const s = serve({ port: 8000 }); console.log("http://localhost:8000/"); for await (const req of s) { req.respond({ body: "Hello World\n" }); }実行はこちら
deno run --allow-net hello_http.ts
「--allow-net」の位置が曲者で最後につけてエラーになり、位置に注意です!
ここtwiiter見てても一度ハマる人が多いようなので。
「--allow-net」はセキュリティの関係で必要みたいです。今後もウォッチしていこう!