MongoDBのリレーション:1対たくさん
〜MongoDBのリレーション〜
今回は1対たくさんの場合を見ていきます。
例えば、商品の生産管理でどの農場でどの商品が作られているかの情報を提供したい時
のケースで記述していきます。
早速書いていきます。
・1対たくさん(One to Many)
まずはスキーマ定義とモデル作成から行います。
mongoose の場合、スキーマ定義の部分で「 ref 」を使うことでリレーションを表現す
ることができます。
mongodb は コレクションに ドキュメント が作成された際に一意なObjectIdが生成され
るため、これを外部キーのように利用してリレーションを表現することが可能です。
次に農場を新規作成する関数を作成します。
実行すると、「まったり牧場」という農場が作成されます。
商品(オブジェクト)としても「メロン・498・夏」の情報になります。
※メロンに関しては先に下記データを挿入しています。
牧場は一つの商品だけということは少なく、複数(たくさん)の商品を扱うことが前提
となるので、これが「1対たくさん」の例に挙げております。
データサイズが巨大になる可能性がある場合や1対数個の直接記述するよりは、
柔軟に使えると感じます。
MongoDBのリレーション:1対数個
〜MongoDBのリレーション〜
ここで言うリレーションはデータの関連付けを指すことになります。
簡単に説明すると、あるSNSに対して、あるツーザーが投稿します。コメントがついた
り、お気に入りができたり、リツートができたりと一つのデータに対して関連性がある
ということです。
早速リレーションについて見ていきましょう。
・1対数個
これが一番シンプルです。
例えば一人のユーザーに対して複数の住所を管理してみます。(Amazonみたいな)
これで追加することができました。
ここから既存のユーザーに住所の追加が可能です。
住所の追加ができました。
数個くらいなら直接ドキュメントにいてれも大丈夫でしょみたいなニュアンスです。
asyncなエラーハンドラ
非同期処理のところでエラーが起きた場合どうなるのでしょうか。
asyncなエラーハンドラについて完成させていきます。
・AppError.js
・index.js
第三引数にnextを渡し、next()の中にエラーを入れることで改善されます。
*1:) => {
例えば商品の詳細ページに遷移した際に、存在しないIDでリクエストを投げた場合、
「product」には中身がなくnullになるため、
「throw new AppError('商品が見つかりません', 404);」が通り、エラーが返ってくる
想定です。
しかしエラーは起きているのですが、うまくリクエストが投げられていませんでした。
asyncの関数内でエラーが発生した際は、next()関数に渡す必要があります。
問題箇所を修正してみます。
カスタムなエラークラスを作成
エラーハンドリングでよく採用されるやり方があります。
一つの例ですが、自分たちのエラークラスを作成するやり方です。
なぜ、クラスを作成するかというとステータスコードだけでエラーの概要を伝えること
ができると便利だからです。
言葉だけでは難しいと思うので、シンプルなエラークラスを作成していきます。
・AppError.js
〜継承を簡単に解説〜
・継承とは、クラスの構造や機能を引き継いだ新しいクラスを定義すること
・extendsキーワードを使って既存のクラスを継承した新しいクラスを定義できる
・継承されるクラスを親クラス、親クラスを継承するクラスを子クラスと呼ぶ
継承した子クラスで親クラスのコンストラクタ(初期化処理)を super() とすることで呼
び出せます。
また自分のプロパティとしてメッセージとステータスを設定しておきます。
これで簡単ではありますが、自分たちの情報を入れられるカスタムなエラークラスの作
成が完了です。
早速、これを使ってみます。
・index.js
index.js で使うために、AppErrorを require しておきます。(下線部)
例えば管理者しかアクセスできないパスにアクセスしてしまったとします。
/admin のパスに行くと、、
AppErrorで設定した、メッセージとステータスコードがしっかりと表示されています。
自分たちで作成したエラークラスが問題なく継承されています。
メッセージ等を指定しなければ、
{ status = 500, message = '何かエラーが起きました' }
が表示されるようになっています。
ちなみに403エラー・・・
閲覧禁止を示すエラーメッセージです。
アクセスしているページはきちんと存在していますが、何らかの理由によりユーザーのアクセスが禁止されて
いるため、ページが見られないエラーです。
カスタムのエラーハンドラを作成する
実用的ではないですが、理解を深めるために簡単なカスタムエラーハンドラを作っていきます。
エラー処理ミドルウェア関数は、その他のミドルウェア関数と同じ方法で定義します。
エラー処理関数の引数は3つではなく、4つ (err、req、res、next) となります。
これを踏まえて記述してみましょう。
太字の部分ですね。
ここで、「error」のパスに行くと、レスポンスが返ってこなくなり、
ログも確認取れます。
自分たちが作成したエラーハンドラが実行されていることになります。
ここで、
を追加します。
問題なく返ってきています。
エラー用のミドルウェアを呼びたいのであれば、「err」を渡す必要があります。
まとめるとこのようになります。
・ログ上・・・コンソールの中身も確認できています。
・画面上・・・上記で設定した「hoge」のエラーがレスポンスとして返ってきます。
あんまり意味がないエラーハンドラですが、自分が作成したエラーが確認でき、複数のエラーも呼ぶことも可能です。
404エラーのルーティング定義
ルーティングを設定していない場所にリクエストが投げられた時、404エラーを返すよ
うにルーティング設定を行います。
404エラー とは、、、
「 404 not found 」:存在しないページにアクセスしようとした時に起こるエラー
他にもHTTPステータスコードが存在するので簡単に紹介します。
もしステータスコードの壁に当たった時に参考にしてみてください。
・100番台 Informational(情報レスポンス)
クライアントからのリクエストを受け入れ可能で、継続して処理されている状態
リクエストとレスポンスは一瞬の出来事のため人間には体感できない程の速さなのでほとんどわからない
・200番台 Success (成功レスポンス)
クライアントからリクエストがサーバに送られ理解されて受理された状態です。成功した後はリクエストに応じてサーバの方で処理をしクライアントにレスポンスを返します。
・300番台 Redirection(リダイレクション)
・400番台 Client Error(クライアントエラー)
ユーザー側で操作や入力に不備があった際に出てしまうエラー
・500番台 Server Error(サーバーエラー)
サーバー側に不備ある場合に起こるエラー。システムが復旧するまで何もできない
早速404エラーを返すルーティングを記述していきます。
一通りのルーティング設定が終わった最後に追加します。
関係のないパスにリクエストを送った際( "/" や "/dogs" 以外)に最終的に404エラー
のルーティングに行き着く流れとなります。
実際に "/cats" というパスにリクエストを送ると、
上記のように記述した404エラーが確認取れます。
自作のミドルウェアを作ってみる
簡単なものですが、自作のミドルウェアを作成してみましょう。
Expressのガイドにも記載がありますが、
「 req , res 」のオブジェクト以外にも第三引数に「 next 」を渡すことができます。
この「 next 」が次のミドルウェアを指す関数となっています。
文字だけではわかりづらいので実際に記述してみます。(_の部分)
連続して出力されています。次の関数が続く限り、呼ばれています。
そして「 next() 」の前に「 return 」を記述することで、「 next() 」以降の処理を無視
するような意味になります。
なので「console.log('初めてのミドルウェアのnextのあとの処理!!!');」というコ
ンソールはログに表示されていません。
誤って、「 next() 」の後ろに何かしらの処理を記述し、それに気づかないと思わぬバグ
になってしまうこともあるので、「 return 」を記述することでそれを防ぐようになって
います。
*1:req, res, next) => {
ログで確認取れました。
「 app.use() 」を使うことで全てのリクエストで処理が実行されるようになっていま
す。(GETやPOST、DELETEなど)
また「 next() 」を記述することで次の関数を呼ぶことになるので、下記のように記述
することも可能です。