//tips
//smart contract
バリデーションで年齢の制限をつけたい時には下記のようにできる。
check('age','AGEは年齢を入力してください。').custom(value=>{
return value >= 0 & value <= 120;
})
このようにcustomを使用することで独自のバリデーションを追加できる。
ここまでのデータベース操作ではsqlでの操作をベースにしていたが、jsからうまくデータベースを操作する方法があり、sequelizeというパッケージを使えばいいよう。
これはOrmと呼ばれるプログラムで、プログラミング言語のオブジェクトとデータベース構造をマッピングし、相互にやり取りすることを可能にするもの。
Node.jsのORMプログラムを利用することでjsからデータベース操作を行なっていく。
npm install sequelize
npm install sequelize-cli
Cliの方はsequelizeを利用するにあたって役に立つコマンドプログラムでオプション。
早速sequelizeの初期化から始める。
npx sequelize-cli init
これを実行するとフォルダーとファイルが生成される。
Config:設定情報を管理するもの
Migrations:データベースの変更情報などを管理するファイル
Models:データベースアクセスに使うモデルというオブジェクトを定義するところ
Seeders:初期データを扱うためのもの
Config.jsonをsqlite対応のものに書き換え。
{
"development": {
"database": "db_development",
"dialect": "sqlite",
"storage": "db_dev.sqlite3"
},
"test": {
"database": "db_test",
"dialect": "sqlite",
"storage": "db_test.sqlite3"
},
"production": {
"database": "db_product",
"dialect": "sqlite",
"storage": "db.sqlite3"
}
}
これでsqlite3がsequelizeで利用できるようになる。
設定ができたらデータベースのテーブルにアクセスするための機能モデルオブジェクトを作成する。テーブルごとに対応するモデルを作成することになる。テーブルから取り出されるレコードもモデルのオブジェクトとして扱える。
早速モデルを作成してみる。
これはスクリプトを書くこともできるが先のcliを利用することでコマンドのみでuser.jsを生成できる。
npx sequelize-cli model:generate --name User --attributes name:string,pass:string,mail:string,age:integer
Name,pass,mail,ageを持つuserモデルを作成した。
--nameと --attributesという2つのオプションを用意し、モデルの名前と属性情報を指定する。
Npxはnpmに用意されている新しいコマンドでnpm以上に便利な機能が組み込まれているよう。sequelize-cliは基本的にnpxで実行する。
中身を確認していくと、
module.exports = (sequelize, DataTypes) => {
で外部利用を可能にし、関数の中ではuserオブジェクトを生成、associateという他のモデルとの関連に関する値を設定、オブジェクトをreturnするという形になっている。
Jsの最初に書かれる'use strict’;は厳格モードというスクリプトチェックが厳しくなるモードで、これを使用することで実行時に解釈が発生しなくなるので実行時間が短縮される。
次にマイグレーションについて見ておく。マイグレーションはデータベースの内容を変更したときに差分をデータベースに適用したり、前の状態に戻したりできる。
新しいモデルを作成した際にはマイグレーションを実行すると作成したモデルなどの情報をもとにデータベースを更新し、必要なテーブルなどを作成してくれる。
つまり、データベースを直接操作することなく、データベースに反映できることになる。
npx sequelize-cli db:migrate --env development
これを実行するとフォルダの中にdb-dev.sqlite3が作成される。
リリース時には—env productionとなる。
db-dev.sqlite3を開いてみると、テーブルの中にusersという項目が作られていることがわかる。
開いてみると、id,name,pass,mail,age,createat,updateatがusersに紐づけられている。
このマイグレーション実行ファイルはmigrationsフォルダに同じく自動生成される。up:async()は作成処理、down:async()は削除処理をになっている。
モデルとそれに対応するデータベースのテーブルは用意できたがまだレコードは何も入っていない。
簡単なダミーデータをあらかじめ入れておきたいので、その場合はシードを作成することになる。これで最初に用意しておくダミーデータができる。
npx sequelize-cli seed:generate --name sample-user
シーディングファイルを作成。seedersフォルダの中にファイルが作成される。そちらを編集してダミーデータを入れる。
'use strict';
module.exports = {
up: async(queryInterface, Sequelize) =>{
return queryInterface.bulkInsert('Users,'[
{
name:'Taro',
pass:'yamada',
mail:'taro@yamada.jp',
name:39,
createdAt:new Date(),
updatedAt:new Date()
},
{
name:'Hanako',
pass:'flower',
mail:'hanako@flower.com',
name:28,
createdAt:new Date(),
updatedAt:new Date()
},
{
name:'Jiro',
pass:'change',
mail:'jiro@change.com',
name:17,
createdAt:new Date(),
updatedAt:new Date()
},
{
name:'sachiko',
pass:'happy',
mail:'sa@happy.jp',
name:6,
createdAt:new Date(),
updatedAt:new Date()
}
]);
},
down:async(queryInterface, Sequelize) =>{
return queryInterface.bulkDelete('Users',null,{});
}
};
書き込んだら下記を実行。これでシーディングが実行される。
npx sequelize-cli db:seed:all
Config.jsonのdevelopmentの設定をもとにシードが作成される。
ここからデータベースのUsersテーブルにアクセスしていく。
今回はhelloではなく、routesフォルダーのusers.jsを使用する。
うまくダミーレコードが反映されない。
Index.ejsのミスタイプが要因だった。
無事に反映。
var express = require('express');
var router = express.Router();
const db=require('../models/');//index
/* GET users listing. */
router.get('/', (req, res, next) =>{
db.User.findAll().then(usrs => {
var data={
title:'Users/Index',
content:usrs
}
res.render('users/index',data);
});
});
// ユーザーのリストをJSON出力する
router.get('/json/', function(req, res, next) {
// Sequelizeのモデルを使ってデータを取得する
db.User.findAll().then(users => {
if (!users) {
console.log("ユーザーデータを取得できませんでした");
res.send('Error');
} else {
res.json(users);
}
});
});
module.exports = router;
Jsonを使ってusersがきちんと取得できているかの確認なども行なった。sqliteのbrowserでテーブルごとにデータ閲覧できることがわかってよかった。
詰まった点で下記参考にした。
https://blog.otasys.co.jp/2019/07/03/express-3/
さらに変形すると、idで絞って検索できるようになる。
router.get('/', (req, res, next) =>{
const id= req.query.id;
db.User.findAll({
where:{
id: id
}
}
).then(usrs => {
var data={
title:'Users/Index',
content:usrs
}
res.render('users/index',data);
});
});
http://localhost:3000/users?id=21として無事に表示された。
指定値だけではなくその前後の値まで検索範囲に含めることができるようにする。そのような場合にはoperatorという値が使われることになる。
const {Op}=require("sequelize");
router.get('/', (req, res, next) =>{
const id= req.query.id;
db.User.findAll({
where:{
id: {[Op.lte]:id}
}
}
).then(usrs => {
var data={
title:'Users/Index',
content:usrs
}
res.render('users/index',data);
});
});
試しにhttp://localhost:3000/users?id=22としてみたら22以下のものを取り出せ、機能した。Op.lteなどのようにあらかじめOpの演算子を知っておく必要がある。
router.get('/', (req, res, next) =>{
const nm= req.query.name;
db.User.findAll({
where:{
name: {[Op.like]:'%'+nm+'%'}
}
}
).then(usrs => {
var data={
title:'Users/Index',
content:usrs
}
res.render('users/index',data);
});
});
類似検索や最大最小範囲内の検索もできる。
db.User.findAll({
where:{
age: {[Op.gte]:min,[Op.lte]:max}
}
}
同様にhttp://localhost:3000/users?name=Taro&mail=hanakoようなこともできる。
router.get('/', (req, res, next) =>{
const nm= req.query.name;
const ml= req.query.mail;
db.User.findAll({
where:{
[Op.or]:[
{name:{[Op.like]:'%'+nm+'%'}},
{mail:{[Op.like]:'%'+ml+'%'}}
]
}