保存版!「sequelize」モデルの使い方実例・全58件さてさて、前回の記事「Node.jsにDBマイグレーション、Seed、モデルを用意する」では、「Sequelize」というパッケージを使ってデータベース周りの開発を楽にしてみました。前回は、その「Sequelize」のインストールやコマンドの使い方をメインにしてご紹介したのですが、実はひとつ情報が多すぎてまとめていない部分があります。それは・・・モデルを使ってデータベース操作(取得/追加/更新/削除)する方法です。そこで!今回は「Sequelize」モデルの使い方を実例でお届けしたいと思います。合わせて読みたい前提として今回の記事は「sequelize」がインストールされていて、さらに、すでにモデルが作成されている必要があります。準備が整っていない場合は、前回記事の「モデルを使う」を参考にしてください。ID番号が1のユーザーデータを取得したい場合は、findByPk()を使います。3)のデータを取得する場合です。5に該当するデータを全て取得する場合です。IDが6のものを探し、もしなければデータを新規登録する場合です。created]と配列になっていることに注意してください。ページ処理のデータを取得する例えば、1ページごとに10件ずつ表示していて、2ページ目のデータを取得したい場合です。条件をみたすデータ});※ちなみにhasOneやhasManyなどの結合を使う場合は、distinctをtrueにしてください。しないと間違った件数が返ってくる可能性があります。省略});※MySQLなどの環境によって、distinctをtrueにするとエラーになってしまう場合があります。これは、DISTINCT(*)という表現が使えないためで、その場合は、includeに空白の配列をセットしてみてください。[]})また、findAndCountAll()は少し不便にもページ処理で重要な「最後のページ番号」や「現在が最後のページかどうか」などの情報を提供してくれません。そのため、以下のようにして計算するといいでしょう。該当するデータの件数を取得する条件に合うデータの「件数」を取得する場合は、count()を使います。該当する最大値を取得する条件に合うデータの最大値を取得する場合はmax()を使います。該当する最小値を取得する条件に合うデータの最小値を取得する場合はmin()を使います。該当するデータの合計を取得する例えば、テストで取得した点数の合計を取得する場合です。条件を指定するsequlizeの条件指定は、専用の比較演算子を使えるようにしておく必要があります。以下のコードを追加しておいてください。SQL文も例として載せていますが、それらは分かりやすく説明するためにテーブル名などを省いた簡略バージョンとなっています。基本的な使い方(特定の値をもつデータを取得)例えばID:3のデータを取得する場合はこのようになります。//});もちろん数値だけでなく、文字列も使えます。WHERE句はこうなります。3また、同じようにしてNULLも問題なく使えますが、その場合WHERE句はISを使う形になる場合があります。メールアドレスが「taro@example.com」で、しかも名前が「太郎」のデータを取得する場合です。//});WHERE句はこのようになります。メールアドレスが「taro@example.com」か、もしくは名前が「次郎」のデータを取得する場合です。//});WHERE句はこのようになります。3」の条件に合うデータを取得する場合です。3」の条件に合うデータを取得する場合です。3」の条件に合うデータを取得する場合です。3」の条件に合うデータを取得する場合です。以外のデータを取得する場合です。equalという意味です。WHERE句はこうなります。3特定の範囲内のデータを取得する例えば、IDが3〜5のデータを取得する場合です。//});特定の範囲「以外」のデータを取得する例えば、IDが3〜5「以外」のデータを取得する場合です。//});指定した複数の値をもつデータを取得する例えば、IDが3と5のものだけを取得する場合です。//});WHERE句はこうなります。以外のデータだけを取得する場合です。//});WHERE句はこうなります。5)あいまい検索する例えば、メールアドレスに「@example」が含まれているデータを取得する場合です。//});また、メールアドレスが「taro@」から始まるデータを取得する場合はこちら。//});そして、メールアドレスが「@example.com」で終わるデータを取得する場合です。//});WHERE句は、それぞれこうなります。'%@example.com'あいまい検索「以外のデータ」を取得する例えば、メールアドレスに「@example」が含まれていないデータを取得する場合です。//});WHERE句はこうなります。'%@example%'指定の値以外のデータを取得する例えば、年齢がnull以外のデータを取得する場合です。//});WHERE句はこうなります。大の順に並べる例えば、年齢の小さい方から並べ替える場合です。小の順に並べる例えば、年齢の大きい方から並べ替える場合です。//});ランダムな順に並べるランダムな順番にデータを並べ替える場合は、次のようにします。sequelizeインスタンスについては、Sequelizeインスタンスを取得するをご覧ください。結合した先で並べ替え例えば、「本」と「本のカテゴリ」が「hasOne(1:1)」で結合していて、「カテゴリ名」で並べ替えを行う場合です。//});指定した値の順で並べ替え例えば、自分で指定したID番号の順に並べ替えをしたい場合です。順で並べ替えるようにしてみます。//});なお、ASCをDESCに変更すると逆順に変更できます。以下のように「スプレッド構文」を使うと、変数にid情報が入っている場合でも楽にコーディングできます。sequelizeインスタンスについては、Sequelizeインスタンスを取得するをご覧ください。※また、利用するSQLによっては使えない場合があります。(MySQLはOKでした)自分で指定する「Sequelize」に頼らず、自分自信でORDER句を指定する場合は、このようになります。sequelizeインスタンスについては、Sequelizeインスタンスを取得するをご覧ください。グループ化する例えば、「本」を「カテゴリID」でグループ化し、カテゴリごとの件数を取得する場合です。//});※複数フィールドでグループ化する場合は、配列で指定してください。sequelizeインスタンスについては、Sequelizeインスタンスを取得するをご覧ください。Usersテーブルから「name」と「email」だけを取得する場合です。//});特定のフィールドを除外する例えば、「createdAt」と「updatedAt」だけ除外してデータ取得する場合です。//});COUNT()でカウントするいわゆるCOUNT()を使いたい場合です。詳しくは、グループ化するをご覧ください。取得する件数を指定する取得するデータ件数を指定する場合です。詳しくは、ページ処理のデータを取得するをご覧ください。取得する開始位置を指定する取得するデータの開始位置を指定する場合です。詳しくは、ページ処理のデータを取得するをご覧ください。Loadingとは、簡単に言うと「2つ以上のテーブルを結合して一気にデータを取得する」ことです。ひとつずつ見ていきましょう!hasOne例えば、「本」のデータに「本のカテゴリ」が1つだけ設定されている、つまり「本」と「本のカテゴリ」が「1:1」の関係で結合する場合です。「models/book.js」を開いてBookモデルにhasOneの結合情報を追加します。Book;};そして、includeを使ってデータ取得します。}});hasMany例えば、「ユーザー」と「ユーザーが投稿したコンテンツ(複数の可能性あり)」を結合した「1:多」の関係になるよう結合する場合です。「models/user.js」を開いてUserモデルにhasManyの結合情報を追加します。User;};そして、includeを使ってデータ取得します。}});BelongsTo例えば、「ユーザー詳細」と「ユーザー」のテーブルが「1:1」の関係で結合する場合です。「models/userdetail.js」を開いてUserDetailモデルにbelongsToの結合情報を追加します。UserDetail;};そして、includeを使ってデータ取得します。}});BelongsToMany例えば、まず以下2つのテーブルがあるとします。ユーザーが投稿した記事そして、ここにもう1つ「ユーザーが【いいね!】をしたデータ」を管理する「PostLikes」テーブルをつくります。この場合、ユーザーから見ると複数の記事に「いいね!」したデータが存在していて、さらに、記事から見ても複数のユーザーが「いいね!」してるので、「多:多」の関係になっています。PostLikesは中間テーブルになっています。記事データを基準として、「いいね!」したユーザーのデータも一緒に取得してみましょう。「models/post.js」を開いてPostモデルにbelongsToManyの結合情報を追加します。ちなみに、分かりやすくするために「likes」という名前をつけています。includeを使ってデータ取得します。以下のようにユーザーテーブルに「firstName(名)」「lastName(姓)」が存在しているとします。データ取得したときにこの2つの値を結合した値「fullName」を取得する場合です。「/models/user.js」を開いて以下のように設定してください。User;};これで、fullNameを通して結合された名前を取得することができます。太郎});なお、もし初期値にFullNameを追加しておきたい場合は以下のようにDataTypes.VIRTUALを使ってください。新太郎」とセットされたら、それぞれ「firstName」と「lastName」にデータセットする場合です。「/models/user.js」を開いて以下のように設定してください。User;};これで、以下のようにすれば「firstName」「lastName」が一気にセットできるようになります。これはサンプルなので実際の開発ではtrim()やバリデーションなどで正しいデータを用意することを忘れないでください。Scopeを使うScopeとは、「検索や並べ替えの条件」を使いまわしができるようにする機能です。あなたのサイトでよく「承認済のユーザー」を抽出することがあるとしましょう。通常であれば、以下のようにその都度whereで指定することになります。}}ただ、毎回毎回この記述をするのはめんどうですし、どこかで記述ミスが作られてしまうかもしれません。そこで、Scopeの登場です。Scopeはこの面倒な部分を「共通化」して、いつでも呼び出せるようにすることができます。scopeグローバル・スコープは、特に設定しなくても必ず追加してくれる条件のことです。「秘密の質問」や「秘密の質問の答え」は、基本的に取得すべきではない特別なデータです。いうことで、以下のようにグローバルスコープを追加してこれらのデータを取得しないようにしてみましょう。省略Scope次に使う時には自分で呼び出して使う通常のスコープです。今回はhasManyの結合をするためのスコープを作ってみましょう。}}でも設定できると書かれていますが、結合を含む場合はうまくいきません。モデルが全て読み込まれていないためです。この「posts」スコープを使うには以下のようにしてください。'friends']).findAll();また、スコープにはパラメーターを渡すこともできます。その場合は、以下のように関数化して設定します。例としてuserIdをパラメーターとして渡してみましょう。});}使い方はこうなります。}).findAll();データを追加する1つだけ追加データを1つ(1行)だけ追加する場合はcreate()を使います。複数のユーザーを一気に追加する場合はbulkCreate()を使います。そのため、Seederなどで重宝するかもしれません。条件に合うデータ全てを更新する場合は、update()を使います。以下はid:1の名前を「真太郎」、メールアドレスを「real-taro@example.com」に変更する場合です。この場合UpdatedAtも自動的に更新されます。save()を使う場合すでにfindOne()などでデータを取得している場合に使える方法です。この場合UpdatedAtも自動的に更新されます。updatedAtの日時だけを更新するupdatedAtは、他のデータが更新された場合に自動的に新しい日時が保存されるようになっているのですが、逆に言うと「他のデータが更新されないなら、ずっと古いまま」という意味になります。そのため、もし手動でupdatedAtだけを更新したい場合は以下のようにします。user.save();});データを削除するfineOne()などでデータ取得されている場合すでにデータ取得されている場合は、インスタンス本体からdestroy()を実行します。条件に合うデータ全てを削除する場合は、モデルのdestroy()を実行します。//});ソフトデリートを使う場合ソフトデリートとは、データベースから実際にデータを削除するのではなく、削除されたことがわかるデータを用意しておき「削除されたもの」として扱う機能のことです。(なぜなら、物理的にデータ削除してしまうと永遠に復活できないからです)ソフトデリートを有効にする「Sequelize」の場合、「deletedAt」というフィールド(初期値:null)を用意し、ここに日付データが入っていれば「削除されたもの」として扱われます。例としてUserモデルにソフトデリート機能をつけてみましょう。マイグレーションは、以下のようにdeletedAtを追加して実行してください。}};テーブルはこうなります。次に「/models/user.js」を開いてparanoidオプションを追加してください。User;};これでソフトデリートが有効になりました。実際に削除してテーブルを確認してみましょう。このように日付が追加されます。この状態でfindAll()してもID:3とID:5のデータは取得されることはありません。ソフトデリートされたデータも含めてデータ取得するもし、ソフトデリートされたデータも含めて取得したい場合はparanoidオプションを使います。//});ソフトデリートせず、物理(完全)削除するソフトデリートを使っているけれども、物理的に削除したいという場合はforceオプションを使います。//});ソフトデリートされたデータを復活させるすでにソフトデリートされたデータを復活させるにはrestore()を使います。user.restore();});直接SQL文を実行する直接SQL文を実行する場合は、query()を使います。//});その他Sequelizeインスタンスを取得する環境による自動切り替えや、少し特殊な内容を作成しようとする場合に「Sequelize」のインスタンスが必要になることがあります。そんな場合は次のようにして取得してください。dialectに「mysql」と直書きしてしまうと環境が変わったときにエラーが発生する可能性があるので少し複雑な形にしていますが、その心配が無い場合は直接書き込んでもいいでしょう。タイムゾーンを指定するSequelizeには、自動的に「createdAt」や「updatedAt」の日時を保存してくれる機能がありますが、実行環境によってはタイムゾーンが正しくない場合があります。そのため、もし日本のタイムゾーンに設定したい場合は、config/config.jsonの中で以下のように設定してください。省略なお、Laravelなどでもよく設定する「Asia/Tokyo」という表現を使うと、次のような警告が表示されることがあります。Connection(超意訳)タイムゾーンが正しくないから無視するね。これ、今は警告だけど将来はエラーになるから(気をつけて〜😏)各SQLの関数を使う例えば、MySQLにはISNULL()という関数がありますが、この関数を使って以下のような順で並べ替える場合です。sequelizeインスタンスについては、Sequelizeインスタンスを取得するをご覧ください。おわりにということで、今回は「Sequelize」のモデルをどのように使うかを実例でご紹介しました。利用できることが多いので少し長い記事になってしまいましたが、ブックマークしてチートシート(カンペ)として使っていただけると嬉しいです。「(どちらが後か先かではなく)似ているので開発しやすい!」でした。SetterやGetterはそのままAccessorとMutatorですし、createdAtやupdatedAt、deletedAtというフィールド名もほぼ同じ。hasManyなどの設定も似ていますよね。そんな中、1点Laravelと違うなと感じたのはWHERE句やORDER句の指定方法です。Laravelはメソッドを使って設定していきますが、Sequelizeではオブジェクトとして一気にセットする形になっています。(ここは、個人的にLaravelの方が使いやすいかな、という感じです。この形式が嫌でCakePHPを使うのをやめましたので・・・😅)例えば、以下のような形がいいな・・・なんて。{});ただ、やはり人気のパッケージだけあって、いまのところ「Node.js」でDB周りの開発をするなら「Sequelize」は外せないだろう、という考えです。皆さんもこの便利さを体験してみてくださいね。開発スキルプログラム開発は15年以上。Laravel、Vue.jsをメインとしてPython(機械学習)やElectronの開発もお引き受けしております。過去2度カナダのバンクーバーに滞在していました。開発状況によりましては開発をお待ちいただく可能性がございますが、いつでもご相談は受けさせていただいております。お気軽にご連絡ください!お問い合わせフォーム開発してほしい機能を募集中!MITライセンスで公開します。詳しくはこちらの記事をご覧ください。ぷれりり・プレスリリース掲載無料のプレスリリース・スタンド!播磨孤道(はりまこどう)兵庫周辺のゆったり自転車一人旅の記事を書いていきます。