(Node.js) sqlite3を使って大量のデータをInsert
概要
sqlite3を使って400件のデータをinsertする処理を行った後に、
DBに登録したデータの総件数を取得しましたが、
なぜか397件しか取得できていなかったため、理由をまとめました。
問題点について
問題点
原因を調査していると他にも問題点がたくさんありました。
1. insertした時のデータが順序通りではなくばらばらになってしまっていた。
2. insertした総件数が正しい値で取得できていなかった。
3. autoincrementが上手く機能せずに空で登録されている
4. データをテキストファイルに書き込む処理にて、登録の順序がばらばら。
400件のinsert自体はうまくいっていたので上記4つを修正しました。
問題ありの修正部分
まず、非同期について考慮していなかったため、
順序通りの登録と、総件数の取得が上手くいっていませんでした。
問題点1と2については、insert部分の書き方とinsert処理が終了した後に総件数を取得するように修正しました。
動的なデータを登録する場合は、SQLインジェクションも考慮して、db.prepare
を使う
insert処理終了後に、コールバックで総件数を取得するsqlを呼び出す。
修正前
// INSERT ALL users.forEach((user, index) => { var insertSql = `insert or replace into user (firstName, lastName, fullName) values (${user.firstName}, ${user.lastName}, ${user.fullName})` DbSetting.DbCommon.getDb().run( insertSql ) fs.appendFile("insert.txt", insertSql, (error) => { if (error) throw err; }); }) // ALL COUNT DbSetting.DbCommon.getDb().get(`select count(*) from user`, (err, row) => { if (err) { console.log(error) } console.log(row["count(*)"]) })
修正後
// db呼び出し var db = DbSetting.DbCommon.getDb() var insertSql = `insert into user (firstName, lastName, fullName) values (? ,? ,?)` var stmt = db.prepare(insertSql) // INSERT ALL users.forEach((user) => { stmt.run(`${user.firstName}`, `${user.lastName}`, `${user.fullName}`); fs.appendFileSync("insert.txt", insertSql, (err) => { if (err) throw err; }); }) stmt.finalize(() => { // ALL COUNT db.get(`select count(*) from user`, (err, row) => { if (err) { console.log(err) } else { console.log(row["count(*)"]) } }) });
問題点3のautoincrementoに関しては書き方を以下のように修正。
NUMBER型では使テーブルは作成されるが、autoincrementされないため、INTEGER型に修正。
NUMBER型だとROWIDとも紐づけが自動でされない模様。
id NUMBER AUTO INCREMENT PRIMARY KEY → userId INTEGER PRIMARY KEY AUTOINCREMENT
問題点4は同期処理に変更
appendFile → appendFileSync
修正後の全体コード
dbCommon.js
var sqlite3 = require('sqlite3').verbose() let db exports.DbCommon = class DbCommon { static init() { db = new sqlite3.Database('sample.db'); } static getDb() { return db } static initCreateTableUser() { db.serialize(() => { // CreateTableUser let CREATE_TABLE_USER = 'CREATE TABLE IF NOT EXISTS User' + '(userId INTEGER PRIMARY KEY AUTOINCREMENT,' + 'firstName TEXT NOT NULL,' + 'lastName TEXT NOT NULL,' + 'fullName TEXT NOT NULL)' db.run(CREATE_TABLE_USER, (error) => { if (error) { console.log(error) } console.log(CREATE_TABLE_USER); }); }) } }
index.js
const DbSetting = require('./dbCommon'); const UserModel = require('./User') const fs = require('fs') // CreateDataBase DbSetting.DbCommon.init(); DbSetting.DbCommon.getDb(); // initCreateTableUser DbSetting.DbCommon.initCreateTableUser() let users = new Array() // users for (var i = 0; i < 400; i++) { users.push(new UserModel.User(i, i, i, i + i)) } // db呼び出し var db = DbSetting.DbCommon.getDb() var insertSql = `insert into user (firstName, lastName, fullName) values (? ,? ,?)` var stmt = db.prepare(insertSql) // INSERT ALL users.forEach((user) => { stmt.run(`${user.firstName}`, `${user.lastName}`, `${user.fullName}`); fs.appendFileSync("insert.txt", `firstName:${user.firstName} lastName:${user.lastName} fullName:${user.fullName}\n`, (err) => { if (err) throw err; }); }) stmt.finalize(() => { // ALL COUNT db.get(`select count(*) from user`, (err, row) => { if (err) { console.log(err) } else { console.log(row["count(*)"]) } }) });
GitHub
参考サイト
勉強会㉚
勉強会
開催日時 2021年7月17日(土) 7:00-9:00
本日は7:00-7:30まで研修会の内容
7:30-8:10,8:30-9:00もくもく。
Vue.jsを始めました。
本日の内容
発表者 | テーマ | 資料 | 時間 |
---|---|---|---|
Nakagawa | 研修について | 30分 |
研修の話
今週の研修会で実装した内容。
疑似要素の話がでてきたので、知ってる知識を少し話す。
::が疑似要素
:の場合は疑似クラス
beforeやafterでcontentsを追加した場合、ドキュメントツリーに存在しないため、コピペができないなど。。。
Vue.js
JavaScriptのフレームワーク
日本語版ドキュメント
jp.vuejs.org
ドキュメントのサンプルを触ってみました。
コンポーネントの基本
var app = new Vue({ el: '#app', data: { message: 1, } })
<div id="app"> {{message}} </div>
グローバルに作成する場合
共通するコンポーネントを登録する場合の書き方
Vue.component('blog-post', { props: ['post'], template: '<div>'+ '<h3>{{post.title}}</h3>'+ '</div>' }); var blog_post_demo = new Vue({ el: "#blog_post_demo", data: { posts: [ { id: 1, title: 'My journey'}, { id: 2, title: 'My Vue'} ] } });
<div id="blog_post_demo"> <blog-post v-for="post in posts" v-bind:id="post.id" v-bind:post="post"> </blog-post> </div>
勉強会㉙
Sharing meeting
開催日時 2021年7月10日(土) 7:00-9:00
本日共有会。
後半は各々開発。
本日の内容
発表者 | テーマ | 資料 | 時間 |
---|---|---|---|
Nakagawa | 研修について | 15分 | |
Toku | 個人アプリ開発 | 15分 |
研修の話
今月から研修開始、主に自宅でVideoを見ながらのオンライン学習
Html,Css,Jqueryを中心に来週からJSPに入る予定。
意外と研修資料がしっかりしているイメージ。
個人的な感想
今後は案件に早い段階で入れるかが勝負だと思います。
未経験からだと周りの話を聞く限りではAWSやLinuxの資格を持ってるのが前提条件として、
インフラの方が現場に入れてる人の話をよく聞く。
プログラミングはまだ厳しそう。
特にSESは即戦力をどうしても求められているので運良くはいれてもかなり苦労します。
個人アプリ
Activityについて。
Chart.jsを使用した、日と週のChart機能を実装中。
できたとこまでお披露目。
github.com
htmlのmeta要素
HTML5プロフェッショナル認定試験
HTML5プロフェッショナル認定試験に出てきそうなmeta要素をメモ程度にまとめる。
Web資格なら「HTML5プロフェッショナル認定試験」公式サイト
meta要素
- meta要素とは・・・Webページに関する情報を埋め込むことができる。
charset
文字コードを指定する
<meta charset="UTF-8">
description
ページの説明を記述
検索された際にタイトル + 説明文が表示される。
こちらの説明文をきっちり書くと、クリック率が上がるらしい。
<meta name="description" content="meta要素のサンプルページ">
dafault-style
優先するスタイルシートの決定
以下の例だとfirstが優先的に指定される。
<meta http-equiv="default-style" content="first"> <link rel="stylesheet" type="text/css" href="sample.css" title="first"> <link rel="stylesheet" type="text/css" href="sample2.css" title="second">
reflesh
Webサイトが引っ越しした際の転送に使われる。
contentが何秒後に転送されるか指定。
urlが引っ越し先のURL。
<meta http-equiv="reflesh" content="3; url="sample2.html">
robots
検索エンジン(クローラー)に対する設定ができる
allがdefault値
<meta name="robots" content="all">
content-security-policy(CSP)
セキュリティーポリシーを設定する
js, css, 画像などの読み込みをサイト自身のオリジンからのみ許可する設定。
XSS対策。
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
- エラー出ましたが、インラインスクリプトを許可する設定
script-src 'sha-256-xxxxxxxxxxxxxxxxxxx='
を埋め込むとエラー解消されました。
<meta http-equiv="Content-Security-Policy" content=default-src 'sha256-xxxxxxxxxxxxxxxxxxx='">
viewport
<meta name="viewport" content="width=device-width, initial-scale=1.0">]
表示領域のこと。
このmeta要素なしでF12にてレスポンシブしてみると非常にわかりやすい。
画面のサイズに合わせて、表示領域を変更してくれる。
いろんなサイトを調べましたが、上記の設定値が最適解な模様。
全体のコード
sample.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="description" content="meta要素のサンプルページ"> <meta http-equiv="default-style" content="first"> <link rel="stylesheet" type="text/css" href="sample.css" title="first"> <link rel="stylesheet" type="text/css" href="sample2.css" title="second"> <meta name="robots" content="all"> <meta http-equiv="Content-Security-Policy" content="default-src 'self';'"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <p class="sample.css">sample</p> <script> window.alert("hello world"); </script> <script src="./sample.js"></script> </body> </html>
sample.css
p{ color:red; }
sample2.css
p{ color:green; }
sample.js
window.alert("hello world");
参考サイト
nature-company.com <meta name="robots">(robotsメタタグ)の正しい使い方と記述時のポイント | デジ研 qiita.com developers.google.com developer.mozilla.org
勉強会㉘
Hands-on and Lightning Talks
開催日時 2021年7月3日(土) 7:00-9:00
本日の発表者は一人!
後半は実務の話を少々。。
本日の内容
発表者 | テーマ | 資料 | 時間 |
---|---|---|---|
Nakagawa | メール機能・アカウント有効化実装中 | 30分 |
メール機能・アカウント有効化実装中
ruby on railsでgemを使ってメール機能作成
google gmailでの送信機能。
gemを使うと良い感じにやってくれるらしい。
本来ならsmtpClientを生成する→サーバー名とport番号を使ってメールサーバーに接続→
メールを作成→送信→メモリ開放、こんな感じの流れになるはず。。
それを簡単にやってのけていたのでgem恐るべし!
Ajax
Ajaxとは??
Asynchronous JavaScript Xml の略
同期通信であれば、クラインアント側の操作がサーバーからのレスポンスを待たなければできなかったが、
JavaScriptのHTTP通信機能(XMLHttpRequest)を用いることで非同期(asynchronous)でサーバーと通信をすることによってサーバーからのレスポンスを待たずにクライアント側が操作できるようになった。
さらに非同期(asynchronous)でサーバーからデータを取得できるため、ページ全体ではなく、ページの一部だけ更新が可能となる。
その結果、サーバー間のトラフィック量も下がる。
e-words.jp
XMLHttpRequest
サーバーとの通信をする際に使うオブジェクト
今回はこちらのオブジェクトを使ってAjaxを実装していく。
GETの場合
やりたいこと
イベントハンドラー
通信の状態が変化した際に取得できるイベントハンドラー
onreadystatechange
を利用せずに以下のイベントでも可能
イベント名 | 意味 |
---|---|
loadstart | リクエスト送信 |
progress | 送受信中 |
timeout | タイムアウト |
abort | リクエスト中断 |
load | リクエスト成功 |
error | リクエスト失敗 |
loadend | リクエスト完了 |
参考サイト
developer.mozilla.org
IPO Calendar API
今回はこちらのAPIを使用しました。
株式市場の上場スケジュールを取得できるAPI
ipo-cal.appspot.com
実装の説明
- xhr.open()
第一引数にメソッド名、第二引数に取得したいデータが存在するURL - xhr.onreadystatechange
通信が成功した際のステータスコード(200)が返却された場合に取得したデータをinnerTextに追記する処理を記述。 - xhr.addEventListener
通信の状態が変化した際のイベントを登録。
通信の流れが知りたいのですべて書いてみる。 - xhr.send()
リクエストを送信 - innerText
なぜinnerTextなのかはこちらを参考にしました。
改行コードを考慮するので使用。
qiita.com
GETの結果
データを取得できているようなので無事成功。
progress... → データ取得 → Success... → Completed... の順番で通信が行われている模様。。
POSTの場合
実装の説明
- xhr.setRequestHeader
どんなデータを送信するかの設定を行います。
content-Type | 種類 |
---|---|
application/x-www-form-urlencoded | テキスト |
application/json | Json |
multipart/form-data | バイナリ形式 |
POSTの結果
Post失敗時の画像
405エラーが返却されて、できませんでした。
ResponseのAllowにPostがないので、POSTはできないようです。
405エラーとは??
全体のコード
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AjaxSample</title> </head> <body> <div> <labe>銘柄コード取得1:</labe> <input id="get_code1" type="text" value=""> <button id="xhr_get_request1">Click_Get_Code1</button> </div> <div> <labe>銘柄コード取得2:</labe> <input id="get_code2" type="text" value=""> <button id="xhr_get_request2">Click_Get_Code2</button> </div> <button id="xhr_post_request">Click_Post</button> <div> <p id="xhr_get_response1"></p> </div> <div> <p id="xhr_get_response2"></p> </div> <div> <p id="xhr_post_response"></p> </div> <script src="./sample.js"></script> </body> </html>
// Ajaxとは?? // Asynchronous JavaScript XML の略 // サーバー側と非同期通信を行い、受信結果をDOM経由でページに反映する仕組み // get const xhr_get_request1 = document.getElementById('xhr_get_request1'); const xhr_get_response1 = document.getElementById('xhr_get_response1'); const xhr_get_request2 = document.getElementById('xhr_get_request2'); const xhr_get_response2 = document.getElementById('xhr_get_response2'); // post const xhr_post_request = document.getElementById('xhr_post_request'); const xhr_post_response = document.getElementById('xhr_post_response'); const get_code1 = document.getElementById('get_code1'); const get_code2 = document.getElementById('get_code2'); xhr_get_request1.addEventListener('click', function () { // 2秒後に実行 setTimeout(xhr_request_method, 2 * 1000, 'http://ipo-cal.appspot.com/api/ipo/', xhr_get_response1, get_code1); }, false); xhr_get_request2.addEventListener('click', function () { // 5秒後に実行 setTimeout(xhr_request_method, 5 * 1000, 'http://ipo-cal.appspot.com/api/ipo/', xhr_get_response2, get_code2); }); // XMLHttpRequest const xhr = new XMLHttpRequest(); // Ajax処理 get_request function xhr_request_method(url, xhr_response, get_code) { xhr.open('GET', url + get_code.value); xhr.send(null); xhr_event(xhr, xhr_response, get_code.id); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { xhr_response.innerText += xhr.responseText + '\n'; } else { xhr_response.innerText += 'failure!!\n'; } } } } // Ajax処理 post_request xhr_post_request.addEventListener('click', function () { xhr.open('POST', './sample.html'); xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded;charset=UTF-8'); xhr.send("text"); xhr.onreadystatechange = function () { if (xhr.readyState === 4) { if (xhr.status === 200) { xhr_post_response.innerText += xhr.responseText + '\n'; } else { xhr_post_response.innerText += 'failure!!\n'; } } } }); // event function xhr_event(_xhr, xhr_response, event_name) { // リクエスト送信をした時 _xhr.addEventListener('loadstart', function () { xhr_response.innerText += `${event_name}:communication...\n`; }); // データを送受信しているとき _xhr.addEventListener('progress', function () { xhr_response.innerText += `${event_name}:progress...\n`; }); // タイムアウトした時 _xhr.addEventListener('timeout', function () { xhr_response.innerText += `${event_name}:timeout...\n`; }); // リクエストがキャンセルされた時 _xhr.addEventListener('abort', function () { xhr_response.innerText += `${event_name}:abort...\n`; }); // リクエストが成功した時 _xhr.addEventListener('load', function () { xhr_response.innerText += `${event_name}:success...\n`; }); // リクエストが失敗した時 _xhr.addEventListener('error', function () { xhr_response.innerText += `${event_name}:error...\n`; }); // リクエストが完了した時 _xhr.addEventListener('loadend', function () { xhr_response.innerText += `${event_name}:completed...\n`; }); }
勉強会㉗
Hands-on and Lightning Talks
開催日時 2021年6月26日(土) 7:00-9:00
今週は共有会、最後にJsonのライブコーディングを行いました。
本日の内容
発表者 | テーマ | 資料 | 時間 |
---|---|---|---|
Nakagawa | 面談の話 | 30分 | |
Kimi | ロビー活動 | 20分 | |
Inaba | 退社の話 | 20分 | |
Toku | Jsonの話 | Json | 20分 |
面談の話
6件受けたが反応が良くない
どの案件も、何かしらのプロジェクト経験が必要
未経験だと現場に入れない
AWS経験をよく聞かれる
ロビー活動
固有名詞が多すぎるのでここには書けませんが、
主にIT関係の人たちの交流会の話。
退社の話
こちらもプライバシー保護のためここには書けませんが、
退社の話したと、これから転職活動をしてく行く話。
Jsonの話
Jsonデータ出力の例
const fs = require('fs'); let jsonFile = fs.readFileSync('./sample.json'); // jsonからobjectに変換 let obj = JSON.parse(jsonFile) // 扱えるデータ出力 console.log(obj); // objectからjsonに変換 let json = JSON.stringify(obj, null, 4) var data = { id: 1, value: 1 }; // json追記 fs.appendFileSync('./sample2.json', JSON.stringify(data) + "\n"); // 読込 let jsonFile2 = fs.readFileSync('./sample2.json', "utf8"); let arrayData = jsonFile2.split('\n'); // 結果 var result = JSON.parse(arrayData[0]);
Jsonの取り扱えるデータ
{ "number": 1, "str": "str", "boolean": true, "null": null, "object": {}, "array": [] }