序章

Node.js を使用していると、データを保存してクエリするプロジェクトを開発していることに気付くかもしれません。 この場合、アプリケーションのデータとクエリの種類に適したデータベースソリューションを選択する必要があります。

このチュートリアルでは、MongoDBデータベースを既存のノードアプリケーションと統合します。 MongoDBのようなNoSQLデータベースは、データ要件にスケーラビリティと柔軟性が含まれている場合に役立ちます。 MongoDBは、 JSON オブジェクトと非同期で動作するように設計されているため、Nodeともうまく統合できます。

MongoDBをプロジェクトに統合するには、 Object Document Mapper (ODM) Mongoose を使用して、アプリケーションデータのスキーマとモデルを作成します。 これにより、 model-view-controller(MVC)アーキテクチャパターンに従ってアプリケーションコードを整理できます。これにより、アプリケーションがユーザー入力を処理する方法のロジックを、データの構造化およびレンダリング方法から分離できます。ユーザー。 このパターンを使用すると、関心の分離をコードベースに導入することで、将来のテストと開発を容易にすることができます。

チュートリアルの最後に、お気に入りのサメに関するユーザーの入力を受け取り、結果をブラウザーに表示する、機能するサメ情報アプリケーションがあります。

前提条件

  • Ubuntu 18.04を実行しているローカル開発マシンまたはサーバーと、root以外のユーザー sudo 特権とアクティブなファイアウォール。 18.04サーバーでこれらをセットアップする方法のガイダンスについては、この初期サーバーセットアップガイドを参照してください。
  • Node.jsとnpmがマシンまたはサーバーにインストールされ、NodeSourceによって管理されるPPAを使用してインストールするためのこれらの手順に従います。
  • Ubuntu 18.04にMongoDBをインストールする方法のステップ1に従って、マシンまたはサーバーにMongoDBをインストールします。

ステップ1—Mongoユーザーを作成する

アプリケーションコードの操作を開始する前に、アプリケーションのデータベースにアクセスできる管理ユーザーを作成します。 このユーザーには、任意のデータベースに対する管理者権限があり、必要に応じて新しいデータベースを切り替えて作成する柔軟性が得られます。

まず、MongoDBがサーバーで実行されていることを確認します。

  1. sudo systemctl status mongodb

次の出力は、MongoDBが実行されていることを示しています。

Output
● mongodb.service - An object/document-oriented database Loaded: loaded (/lib/systemd/system/mongodb.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2019-01-31 21:07:25 UTC; 21min ago ...

次に、Mongoシェルを開いてユーザーを作成します。

  1. mongo

これにより、管理シェルに移動します。

Output
MongoDB shell version v3.6.3 connecting to: mongodb://127.0.0.1:27017 MongoDB server version: 3.6.3 ... >

シェルへの無制限のアクセスにより、シェルを開くと、いくつかの管理上の警告が表示されます。 admin データベース。 このアクセスの制限について詳しくは、 Ubuntu 16.04にMongoDBをインストールして保護する方法を読んで、本番環境に移行する際に確認してください。

今のところ、あなたはへのアクセスを使用することができます admin データベースを使用して、 userAdminAnyDatabase 権限を持つユーザーを作成します。これにより、アプリケーションのデータベースへのパスワードで保護されたアクセスが可能になります。

シェルで、使用することを指定します admin ユーザーを作成するためのデータベース:

  1. use admin

次に、ユーザー名とパスワードを追加して、役割とパスワードを作成します。 db.createUser 指図。 このコマンドを入力すると、コマンドが完了するまで、シェルは各行の前に3つのドットを追加します。 ここに記載されているユーザーとパスワードは、必ず自分のユーザー名とパスワードに置き換えてください。

  1. db.createUser(
  2. {
  3. user: "sammy",
  4. pwd: "your_password",
  5. roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
  6. }
  7. )

これにより、ユーザーのエントリが作成されます sammy の中に admin データベース。 選択したユーザー名と admin データベースはユーザーの識別子として機能します。

プロセス全体の出力は次のようになります。これには、エントリが成功したことを示すメッセージが含まれます。

Output
> db.createUser( ... { ... user: "sammy", ... pwd: "your_password", ... roles: [ { role: "userAdminAnyDatabase", db: "admin" } ] ... } ...) Successfully added user: { "user" : "sammy", "roles" : [ { "role" : "userAdminAnyDatabase", "db" : "admin" } ] }

ユーザーとパスワードを作成したら、Mongoシェルを終了できます。

  1. exit

データベースユーザーを作成したので、スタータープロジェクトコードのクローンを作成し、Mongooseライブラリを追加します。これにより、データベース内のコレクションのスキーマとモデルを実装できます。

ステップ2—マングースとデータベースの情報をプロジェクトに追加する

次のステップは、アプリケーションスターターコードのクローンを作成し、MongooseとMongoDBデータベース情報をプロジェクトに追加することです。

root以外のユーザーのホームディレクトリで、 DigitalOceanCommunityGitHubアカウントからnodejs-image-demoリポジトリのクローンを作成します。 このリポジトリには、Dockerを使用してNode.jsアプリケーションを構築する方法で説明されているセットアップのコードが含まれています。

リポジトリをと呼ばれるディレクトリに複製します node_project:

  1. git clone https://github.com/do-community/nodejs-image-demo.git node_project

に変更します node_project ディレクトリ:

  1. cd node_project

プロジェクトコードを変更する前に、を使用してプロジェクトの構造を見てみましょう。 tree 指図。

ヒント: tree コマンドラインからファイルとディレクトリの構造を表示するための便利なコマンドです。 次のコマンドでインストールできます。

  1. sudo apt install tree

使用するには、 cd 指定されたディレクトリに入力し、次のように入力します tree. 次のようなコマンドを使用して、開始点へのパスを指定することもできます。

  1. tree /home/sammy/sammys-project

次のように入力して、 node_project ディレクトリ:

  1. tree

現在のプロジェクトの構造は次のようになります。

Output
├── Dockerfile ├── README.md ├── app.js ├── package-lock.json ├── package.json └── views ├── css │ └── styles.css ├── index.html └── sharks.html

チュートリアルを進めながら、このプロジェクトにディレクトリを追加します。 tree 進捗状況を追跡するのに役立つコマンドになります。

次に、 mongoose プロジェクトへのnpmパッケージ npm install 指図:

  1. npm install mongoose

このコマンドは、 node_modules プロジェクトのディレクトリにリストされている依存関係を使用して、プロジェクトディレクトリ内のディレクトリ package.json ファイル、および追加します mongoose そのディレクトリに。 また、追加されます mongoose にリストされている依存関係に package.json ファイル。 のより詳細な議論のために package.jsonDockerを使用してNode.jsアプリケーションを構築する方法のステップ1を参照してください。

Mongooseスキーマまたはモデルを作成する前に、アプリケーションがデータベースに接続できるように、データベース接続情報を追加します。

アプリケーションの懸念事項を可能な限り分離するために、データベース接続情報用に次のような別のファイルを作成します。 db.js. このファイルは次のコマンドで開くことができます nano またはお気に入りの編集者:

  1. nano db.js

まず、インポートします mongoose モジュールを使用して require 関数:

〜/ node_project / db.js
const mongoose = require('mongoose');

これにより、データベースへの接続を作成するために使用するMongooseの組み込みメソッドにアクセスできるようになります。

次に、次の定数を追加して、Mongoの接続URIの情報を定義します。 ユーザー名とパスワードはオプションですが、データベースの認証を要求できるように、これらを含めます。 以下にリストされているユーザー名とパスワードを自分の情報に置き換えてください。データベースを他の名前で自由に呼び出してください。 'sharkinfo' 必要に応じて:

〜/ node_project / db.js
const mongoose = require('mongoose');

const MONGO_USERNAME = 'sammy';
const MONGO_PASSWORD = 'your_password';
const MONGO_HOSTNAME = '127.0.0.1';
const MONGO_PORT = '27017';
const MONGO_DB = 'sharkinfo';

データベースをローカルで実行しているため、 127.0.0.1 ホスト名として。 これは、他の開発コンテキストで変更されます。たとえば、個別のデータベースサーバーを使用している場合や、コンテナー化されたワークフローで複数のノードを操作している場合などです。

最後に、URIの定数を定義し、 mongoose.connect()メソッドを使用して接続を作成します。

〜/ node_project / db.js
...
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;

mongoose.connect(url, {useNewUrlParser: true});

URIで指定したことに注意してください authSource 私たちのユーザーのために admin データベース。 これは、接続文字列にユーザー名を指定したために必要です。 を使用して useNewUrlParser フラグ mongoose.connect() Mongoの新しいURLパーサーを使用することを指定します。

編集が終了したら、ファイルを保存して閉じます。

最後のステップとして、データベース接続情報をに追加します app.js アプリケーションがそれを使用できるようにファイルします。 開ける app.js:

  1. nano app.js

ファイルの最初の行は次のようになります。

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();

const path = __dirname + '/views/';
...

router ファイルの先頭近くにある定数定義に、次の行を追加します。

〜/ node_project / app.js
...
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
...

これは、で指定されたデータベース接続情報を使用するようにアプリケーションに指示します。 db.js.

編集が終了したら、ファイルを保存して閉じます。

データベース情報を配置し、Mongooseをプロジェクトに追加すると、データを形成するスキーマとモデルを作成する準備が整います。 sharks コレクション。

ステップ3—マングースのスキーマとモデルを作成する

次のステップは、 sharks ユーザーが作成するコレクション sharkinfo それらの入力を持つデータベース。 これらの作成されたドキュメントにどのような構造を持たせたいですか? 現在のアプリケーションのサメ情報ページには、さまざまなサメとその行動に関する詳細が含まれています。

このテーマに沿って、ユーザーに全体的な性格の詳細を含む新しいサメを追加してもらうことができます。 この目標は、スキーマの作成方法を形作ります。

スキーマとモデルをアプリケーションの他の部分と区別するために、 models 現在のプロジェクトディレクトリ内のディレクトリ:

  1. mkdir models

次に、というファイルを開きます sharks.js スキーマとモデルを作成するには:

  1. nano models/sharks.js

をインポートします mongoose ファイルの先頭にあるモジュール:

〜/ node_project / models / sharks.js
const mongoose = require('mongoose');

この下に、 Schema sharkスキーマの基礎として使用するオブジェクト:

〜/ node_project / models / sharks.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

これで、スキーマに含めるフィールドを定義できます。 個々のサメとその行動に関する情報を含むコレクションを作成したいので、 name キーcharacter 鍵。 以下を追加します Shark 定数定義の下のスキーマ:

〜/ node_project / models / sharks.js
...
const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

この定義には、ユーザーに期待される入力のタイプ(この場合は、 string )と、その入力が必要かどうかに関する情報が含まれています。

最後に、 Shark Mongooseのmodel()関数を使用したモデル。 このモデルを使用すると、コレクションからドキュメントをクエリして、新しいドキュメントを検証できます。 ファイルの最後に次の行を追加します。

〜/ node_project / models / sharks.js
...
module.exports = mongoose.model('Shark', Shark)

この最後の行は私たちを作ります Shark module.exportsプロパティを使用してモジュールとして利用可能なモデル。 このプロパティは、モジュールがエクスポートする値を定義し、アプリケーションの他の場所で使用できるようにします。

完成した models/sharks.js ファイルは次のようになります。

〜/ node_project / models / sharks.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const Shark = new Schema ({
        name: { type: String, required: true },
        character: { type: String, required: true },
});

module.exports = mongoose.model('Shark', Shark)

編集が終了したら、ファイルを保存して閉じます。

とともに Shark スキーマとモデルが整ったら、アプリケーションがユーザー入力を処理する方法を決定するロジックの作業を開始できます。

ステップ4—コントローラーの作成

次のステップは、ユーザー入力をデータベースに保存してユーザーに返す方法を決定するコントローラーコンポーネントを作成することです。

まず、コントローラーのディレクトリを作成します。

  1. mkdir controllers

次に、そのフォルダ内のファイルを開きます。 sharks.js:

  1. nano controllers/sharks.js

ファイルの先頭に、モジュールをインポートします。 Shark コントローラのロジックで使用できるようにモデル化します。 また、パスモジュールをインポートして、ユーザーがサメを入力するフォームへのパスを設定できるユーティリティにアクセスします。

以下を追加します require ファイルの先頭まで機能します。

〜/ node_project / controllers / sharks.js
const path = require('path');
const Shark = require('../models/sharks');

次に、ノードのエクスポートショートカットを使用して、コントローラーモジュールでエクスポートする一連の関数を記述します。 これらの関数には、ユーザーのサメデータに関連する3つのタスクが含まれます。

  • ユーザーにサメの入力フォームを送信します。
  • 新しいサメのエントリを作成します。
  • サメをユーザーに表示します。

まず、作成します index 入力フォームでサメのページを表示する関数。 インポートの下にこの関数を追加します。

〜/ node_project / controllers / sharks.js
...
exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

次に、以下 index 関数、と呼ばれる関数を追加します create あなたの新しいサメのエントリを作成するには sharks コレクション:

〜/ node_project / controllers / sharks.js
...
exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

この関数は、ユーザーがサメのデータをフォームに投稿したときに呼び出されます。 sharks.html ページ。 チュートリアルの後半でアプリケーションのルートを作成するときに、このPOSTエンドポイントを使用してルートを作成します。 とともに body POSTリクエストの create 関数は、ここでは呼ばれる新しいサメドキュメントオブジェクトを作成します newShark、を使用して Shark インポートしたモデル。 POSTメソッドが意図したとおりに機能していることを確認するために、コンソールにsharkエントリを出力する console.logメソッドを追加しましたが、必要に応じてこれを省略してください。

を使用して newShark オブジェクト、 create 次に、関数はMongooseの model.save()メソッドを呼び出し、で定義したキーを使用して新しいサメのドキュメントを作成します。 Shark モデル。 このコールバック関数は、標準ノードコールバックパターンに従います。 callback(error, results). エラーの場合は、エラーを報告するメッセージをユーザーに送信し、成功した場合は、 res.redirect()メソッドを使用して、ユーザーをエンドポイントに送信します。彼らのサメの情報をブラウザで彼らに返します。

最後に、 list 関数は、コレクションのコンテンツをユーザーに表示します。 以下のコードを追加します create 関数:

〜/ node_project / controllers / sharks.js
...
exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

この関数は、 Shark マングースのmodel.find()メソッドを使用してモデル化し、入力されたサメを返します。 sharks コレクション。 これは、クエリオブジェクトを返すことによって行われます。この場合、 sharks コレクション—約束として、Mongooseの exec()関数を使用します。 エラーの場合、コールバック関数は500エラーを送信します。

返されたクエリオブジェクト sharks コレクションはでレンダリングされます getshark 次のステップでEJSテンプレート言語を使用して作成するページ。

完成したファイルは次のようになります。

〜/ node_project / controllers / sharks.js
const path = require('path');
const Shark = require('../models/sharks');

exports.index = function (req, res) {
    res.sendFile(path.resolve('views/sharks.html'));
};

exports.create = function (req, res) {
    var newShark = new Shark(req.body);
    console.log(req.body);
    newShark.save(function (err) {
            if(err) {
            res.status(400).send('Unable to save shark to database');
        } else {
            res.redirect('/sharks/getshark');
        }
  });
               };

exports.list = function (req, res) {
        Shark.find({}).exec(function (err, sharks) {
                if (err) {
                        return res.send(500, err);
                }
                res.render('getshark', {
                        sharks: sharks
             });
        });
};

ここでは矢印関数を使用していませんが、独自の開発プロセスでこのコードを反復処理するときに、それらを含めることをお勧めします。

編集が終了したら、ファイルを保存して閉じます。

次のステップに進む前に、次の手順を実行できます tree 再びあなたから node_project この時点でプロジェクトの構造を表示するディレクトリ。 今回は、簡潔にするために、 tree 省略します node_modules を使用するディレクトリ -I オプション:

  1. tree -I node_modules

追加を行うと、プロジェクトの構造は次のようになります。

Output
├── Dockerfile ├── README.md ├── app.js ├── controllers │ └── sharks.js ├── db.js ├── models │ └── sharks.js ├── package-lock.json ├── package.json └── views ├── css │ └── styles.css ├── index.html └── sharks.html

これで、ユーザー入力を保存してユーザーに返す方法を指示するコントローラーコンポーネントができたので、コントローラーのロジックを実装するビューの作成に進むことができます。

ステップ5—EJSおよびExpressミドルウェアを使用したデータの収集とレンダリング

アプリケーションがユーザーデータを処理できるようにするために、2つのことを行います。1つは、アプリケーションがユーザーの入力データを解析できるようにする組み込みのExpressミドルウェア関数 urlencoded()を含めることです。 。 次に、ビューにテンプレートタグを追加して、コード内のユーザーデータとの動的な相互作用を可能にします。

Expressと連携するには urlencoded() 機能、最初にあなたの app.js ファイル:

  1. nano app.js

あなたの上に express.static() 関数、次の行を追加します。

〜/ node_project / app.js
...
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
...

この関数を追加すると、サメ情報フォームから解析されたPOSTデータにアクセスできるようになります。 指定しています true とともに extended アプリケーションが解析するデータのタイプ(ネストされたオブジェクトなどを含む)の柔軟性を高めるためのオプション。 オプションの詳細については、機能ドキュメントを参照してください。

編集が終了したら、ファイルを保存して閉じます。

次に、ビューにテンプレート機能を追加します。 まず、ejsパッケージをインストールします。 npm install:

  1. npm install ejs

次に、 sharks.html のファイル views フォルダ:

  1. nano views/sharks.html

ステップ3では、このページを見て、マングースのスキーマとモデルをどのように作成するかを決定しました。

ここでは、2列の layout ではなく、ユーザーがサメに関する情報を入力できるフォームを備えた3番目の列を紹介します。

最初のステップとして、既存の列の寸法を次のように変更します 4 3つの同じサイズの列を作成します。 現在読んでいる2行でこの変更を行う必要があることに注意してください <div class="col-lg-6">. これらは両方ともなります <div class="col-lg-4">:

〜/ node_project / views / sharks.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
    </div>
  </div>

 </html> 

行と列のレイアウトを含むBootstrapのグリッドシステムの概要については、このBootstrapの概要を参照してください。

次に、POSTリクエストの名前付きエンドポイントを含む別の列を追加します。この列には、ユーザーのsharkデータとそのデータをキャプチャするEJSテンプレートタグが含まれます。 このコラムはクロージングを下回ります </p></div> 前の列のタグで、行、コンテナ、およびHTMLドキュメントの終了タグの上にあります。 これらの終了タグは、コードにすでに配置されています。 それらはまたコメントで下にマークされています。 次のコードを追加して新しい列を作成するときは、そのままにしておきます。

〜/ node_project / views / sharks.html
...
       </p> <!-- closing p from previous column -->
   </div> <!-- closing div from previous column -->
<div class="col-lg-4">
            <p>
                <form action="/sharks/addshark" method="post">
                    <div class="caption">Enter Your Shark</div>
                    <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
                    <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
                    <button type="submit">Submit</button>
                </form>
            </p>
        </div> 
    </div> <!-- closing div for row -->
</div> <!-- closing div for container -->

</html> <!-- closing html tag -->

の中に form タグ、あなたは追加しています "/sharks/addshark" ユーザーのサメデータのエンドポイントと、それを送信するPOSTメソッドを指定します。 入力フィールドでは、次のフィールドを指定しています。 "Shark Name""Shark Character"、に合わせて Shark 前に定義したモデル。

ユーザー入力をに追加するには sharks コレクション、EJSテンプレートタグを使用しています(<%=, %>)JavaScript構文とともに、ユーザーのエントリを新しく作成されたドキュメントの適切なフィールドにマップします。 JavaScriptオブジェクトの詳細については、JavaScriptオブジェクトについての記事を参照してください。 EJSテンプレートタグの詳細については、EJSドキュメントを参照してください。

shark入力フォームの列を含む、3つの列すべてを含むコンテナ全体は、終了すると次のようになります。

〜/ node_project / views / sharks.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
	<div class="col-lg-4">
            <p>
                <form action="/sharks/addshark" method="post">
                    <div class="caption">Enter Your Shark</div>
                    <input type="text" placeholder="Shark Name" name="name" <%=sharks[i].name; %>
                    <input type="text" placeholder="Shark Character" name="character" <%=sharks[i].character; %>
                    <button type="submit">Submit</button>
                </form>
            </p>
        </div>
    </div>
  </div>

</html>

編集が終了したら、ファイルを保存して閉じます。

ユーザーの入力を収集する方法ができたので、返されたサメとそれに関連するキャラクター情報を表示するエンドポイントを作成できます。

新しく変更したものをコピーします sharks.html と呼ばれるファイルへのファイル getshark.html:

  1. cp views/sharks.html views/getshark.html

開ける getshark.html:

  1. nano views/getshark.html

ファイル内で、サメの入力フォームを作成するために使用した列を、サメを表示する列に置き換えることで変更します。 sharks コレクション。 繰り返しますが、コードは既存のものの間に入ります </p></div> 前の列のタグと、行、コンテナ、およびHTMLドキュメントの終了タグ。 次のコードを追加して列を作成するときは、これらのタグをそのままにしておくことを忘れないでください。

〜/ node_project / views / getshark.html
...
       </p> <!-- closing p from previous column -->
   </div> <!-- closing div from previous column -->
<div class="col-lg-4">
           <p>
              <div class="caption">Your Sharks</div>
                  <ul>
                     <% sharks.forEach(function(shark) { %>
                        <p>Name: <%= shark.name %></p>
                        <p>Character: <%= shark.character %></p>
                     <% }); %>
                  </ul>
            </p>
        </div>
    </div> <!-- closing div for row -->
</div> <!-- closing div for container -->

</html> <!-- closing html tag -->

ここでは、EJSテンプレートタグと forEach()メソッドを使用して、各値を出力しています。 sharks 最近追加されたサメに関する情報を含むコレクション。

3つの列すべてを含むコンテナ全体( sharks コレクションは、終了すると次のようになります。

〜/ node_project / views / getshark.html
...
<div class="container">
    <div class="row">
        <div class="col-lg-4">
            <p>
                <div class="caption">Some sharks are known to be dangerous to humans, though many more are not. The sawshark, for example, is not considered a threat to humans.
                </div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sawshark.jpg" alt="Sawshark">
            </p>
        </div>
        <div class="col-lg-4">
            <p>
                <div class="caption">Other sharks are known to be friendly and welcoming!</div>
                <img src="https://assets.digitalocean.com/articles/docker_node_image/sammy.png" alt="Sammy the Shark">
            </p>
        </div>
	<div class="col-lg-4">
            <p>
              <div class="caption">Your Sharks</div>
                  <ul>
                     <% sharks.forEach(function(shark) { %>
                        <p>Name: <%= shark.name %></p>
                        <p>Character: <%= shark.character %></p>
                     <% }); %>
                  </ul>
            </p>
        </div>
    </div>
  </div>

</html>

編集が終了したら、ファイルを保存して閉じます。

作成したテンプレートをアプリケーションで使用するには、数行を追加する必要があります。 app.js ファイル。 もう一度開きます。

  1. nano app.js

追加した場所の上 express.urlencoded() 関数、次の行を追加します。

〜/ node_project / app.js
...
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));

...

app.engine メソッドは、EJSテンプレートエンジンをHTMLファイルにマップするようにアプリケーションに指示します。 app.set は、デフォルトのビューエンジンを定義します。

君の app.js ファイルは次のようになります。

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');

const path = __dirname + '/views/';
const port = 8080;

router.use(function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path + 'index.html');
});

router.get('/sharks',function(req,res){
  res.sendFile(path + 'sharks.html');
});

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/', router);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

ユーザーデータを動的に操作できるビューを作成したので、次に、プロジェクトのルートを作成して、ビューとコントローラーロジックをまとめます。

ステップ6—ルートを作成する

アプリケーションのコンポーネントをまとめる最後のステップは、ルートを作成することです。 アプリケーションのランディングページへのルートとサメのページへの別のルートを含め、機能ごとにルートを分けます。 私たちの sharks ルートは、コントローラーのロジックを前のステップで作成したビューと統合する場所になります。

まず、作成します routes ディレクトリ:

  1. mkdir routes

次に、というファイルを開きます index.js このディレクトリ内:

  1. nano routes/index.js

このファイルは最初に express, router、 と path オブジェクトを使用して、エクスポートするルートを定義できます。 router オブジェクト、およびファイルパスを動的に操作できるようにします。 ファイルの先頭に次のコードを追加します。

〜/ node_project / routers / index.js
const express = require('express');
const router = express.Router();
const path = require('path');

次に、以下を追加します router.use 関数。ルーターの要求をログに記録してアプリケーションのルートに渡すミドルウェア関数をロードします。

〜/ node_project / routers / index.js
...

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

アプリケーションのルートへのリクエストは最初にここに送信され、ここからユーザーはアプリケーションのランディングページ(次に定義するルート)に移動します。 以下のコードを追加します router.use ランディングページへのルートを定義する関数:

〜/ node_project / routers / index.js
...

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

ユーザーがアプリケーションにアクセスしたときに、最初に送信したいのは index.html 私たちが持っているランディングページ views ディレクトリ。

最後に、これらのルートをアプリケーションの他の場所にインポート可能なモジュールとしてアクセスできるようにするには、ファイルの最後に終了式を追加して、 router 物体:

〜/ node_project / routers / index.js
...

module.exports = router;

完成したファイルは次のようになります。

〜/ node_project / routers / index.js
const express = require('express');
const router = express.Router();
const path = require('path');

router.use (function (req,res,next) {
  console.log('/' + req.method);
  next();
});

router.get('/',function(req,res){
  res.sendFile(path.resolve('views/index.html'));
});

module.exports = router;

編集が終了したら、このファイルを保存して閉じます。

次に、というファイルを開きます sharks.js ユーザーのサメの入力を処理するために作成したさまざまなエンドポイントとビューをアプリケーションがどのように使用するかを定義するには、次のようにします。

  1. nano routes/sharks.js

ファイルの先頭で、 expressrouter オブジェクト:

〜/ node_project / routers / sharks.js
const express = require('express');
const router = express.Router();

次に、というモジュールをインポートします shark これにより、コントローラーで定義したエクスポートされた関数を操作できるようになります。

〜/ node_project / routers / sharks.js
const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

これで、を使用してルートを作成できます index, create、 と list で定義した関数 sharks コントローラファイル。 各ルートは適切なHTTPメソッドに関連付けられます。メインのサメ情報のランディングページをレンダリングしてサメのリストをユーザーに返す場合はGET、新しいサメのエントリを作成する場合はPOSTです。

〜/ node_project / routers / sharks.js
...

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

各ルートは、の関連機能を利用しています controllers/sharks.js、このファイルの先頭にインポートすることで、そのモジュールにアクセスできるようにしたためです。

最後に、これらのルートをに添付してファイルを閉じます router オブジェクトとそれらのエクスポート:

〜/ node_project / routers / index.js
...

module.exports = router;

完成したファイルは次のようになります。

〜/ node_project / routers / sharks.js
const express = require('express');
const router = express.Router();
const shark = require('../controllers/sharks');

router.get('/', function(req, res){
    shark.index(req,res);
});

router.post('/addshark', function(req, res) {
    shark.create(req,res);
});

router.get('/getshark', function(req, res) {
    shark.list(req,res);
});

module.exports = router;

編集が終了したら、ファイルを保存して閉じます。

これらのルートをアプリケーションにアクセスできるようにする最後のステップは、これらのルートをに追加することです。 app.js. そのファイルをもう一度開きます。

  1. nano app.js

あなたの下に db 定数の場合、ルートに次のインポートを追加します。

〜/ node_project / app.js
...
const db = require('./db');
const sharks = require('./routes/sharks');

次に、置換 app.use 現在あなたをマウントする関数 router 次の行のオブジェクト。これにより、 sharks ルーターモジュール:

〜/ node_project / app.js
...
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
        console.log("Example app listening on port 8080!")
})

アプリケーションのルートを使用してインポートしているため、このファイルで以前に定義されたルートを削除できるようになりました。 sharks ルーターモジュール。

あなたの最終バージョン app.js ファイルは次のようになります。

〜/ node_project / app.js
const express = require('express');
const app = express();
const router = express.Router();
const db = require('./db');
const sharks = require('./routes/sharks');

const path = __dirname + '/views/';
const port = 8080;

app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path));
app.use('/sharks', sharks);

app.listen(port, function () {
  console.log('Example app listening on port 8080!')
})

編集が終了したら、ファイルを保存して閉じます。

これで実行できます tree プロジェクトの最終的な構造をもう一度確認するには、次のようにします。

  1. tree -I node_modules

プロジェクト構造は次のようになります。

Output
├── Dockerfile ├── README.md ├── app.js ├── controllers │ └── sharks.js ├── db.js ├── models │ └── sharks.js ├── package-lock.json ├── package.json ├── routes │ ├── index.js │ └── sharks.js └── views ├── css │ └── styles.css ├── getshark.html ├── index.html └── sharks.html

すべてのアプリケーションコンポーネントが作成され、配置されたら、データベースにテストサメを追加する準備が整いました。

前提条件の初期サーバーセットアップチュートリアルに従った場合、ファイアウォールは現在SSHトラフィックのみを許可しているため、ファイアウォールを変更する必要があります。 ポートへのトラフィックを許可するには 8080 走る:

  1. sudo ufw allow 8080

アプリケーションを起動します。

  1. node app.js

次に、ブラウザを次の場所に移動します http://your_server_ip:8080. 次のランディングページが表示されます。

Get SharkInfoボタンをクリックします。 サメの入力フォームが追加された次の情報ページが表示されます。

フォームに、選択したサメを追加します。 このデモンストレーションの目的で、追加します Megalodon Shark Shark Name フィールドに移動し、 Ancient Shark Character フィールドへ:

送信ボタンをクリックします。 このサメの情報が表示されたページが表示されます。

また、サメがコレクションに追加されたことを示す出力がコンソールに表示されます。

Output
Example app listening on port 8080! { name: 'Megalodon Shark', character: 'Ancient' }

新しいサメのエントリを作成する場合は、サメページに戻り、サメを追加するプロセスを繰り返します。

これで、ユーザーがお気に入りのサメに関する情報を追加できる、機能するサメ情報アプリケーションができました。

結論

このチュートリアルでは、MongoDBデータベースを統合し、MVCアーキテクチャパターンを使用してアプリケーションのロジックを書き直すことで、Nodeアプリケーションを構築しました。 このアプリケーションは、本格的なCRUDアプリケーションの出発点として適しています。

他のコンテキストでのMVCパターンに関するその他のリソースについては、Django開発シリーズまたはDjangoを使用して顧客情報を管理しUbuntu18.04でReactする最新のWebアプリケーションを構築する方法を参照してください。

MongoDBの操作の詳細については、MongoDBチュートリアルのライブラリを参照してください。