Tutorial

Интеграция MongoDB с вашим приложением Node

Published on January 24, 2020
Русский
Интеграция MongoDB с вашим приложением Node

Введение

При работе с Node.js вы можете столкнуться с ситуацией, когда вы разрабатываете проект, который будет сохранять и запрашивать данные. В данном случае вам нужно будет выбрать решение для базы данных, которое будет отвечать характеристикам данных приложения и типов запросов.

В этом обучающем руководстве вы будете интегрировать базу данных MongoDB с существующим приложением Node. NoSQL базы данных, такие как MongoDB, могут быть полезными, если список ваших требований для данных включают масштабируемость и гибкость. MongoDB отлично интегрируется с Node, поскольку она предназначена для асинхронной работы с объектами JSON.

Для интеграции MongoDB с вашим проектом вы будете использовать Object Document Mapper (ODM) Mongoose для создания схем и моделей данных вашего приложения. Это позволит вам организовать код приложения в соответствии с архитектурным шаблоном модель-представление-контроллер (MVC), который позволяет отделить логику обработки вводимых пользователей данных и логику структурирования данных и их отображения для пользователя. Использование такого шаблона может упрощать будущие тестирование и разработку, реализуя разделение проблем в базе кода.

После прохождения руководства у вас будет рабочее приложение с информацией об акулах, которое будет принимать вводимые пользователем данные об их любимых акулах и отображать результаты в браузере:

Вывод акулы

Предварительные требования

Шаг 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. Дополнительную информацию об ограничении такого доступа см. в руководстве «Установка и обеспечение безопасности MongoDB на Ubuntu 16.04», которая будет полезна вам при переходе к финальной настройке.

А сейчас вы можете воспользоваться своим доступом к базе данных admin для создания пользователя с привилегиями userAdminAnyDatabase, которые позволят получать защищенный паролем доступ к базам данных вашего приложения.

в командной строке укажите, что вы хотите использовать базу данных admin для создания вашего пользователя:

  1. use admin

Далее создайте роль и пароль, добавив имя пользователя и пароль с помощью команды db.createUser. Когда вы введете эту команду, командная строка будет добавлять три точки перед каждой строкой, пока работа команды не будет завершена. Обязательно замените пользователя и пароль, предоставленные здесь, на ваши имя пользователя и пароль:

  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 и базе данных в проект

Нашими следующими действия будут клонирование начального кода приложения и добавление в проект информации о Mongoose и нашей базе данных MongoDB.

В корневой директории пользователя без прав root клонируйте репозиторий nodejs-image-demo из учетной записи DigitalOcean на GitHub. Этот репозиторий содержит код настройки, описанной в руководстве Сборка приложения Node.js с помощью Docker.

Клонируйте репозиторий в директорию с именем 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.json см. в шаге 1 руководства по сборке приложения Node.js с помощью Docker.

Перед созданием любых схем или моделей мы добавим информацию о подключении базы данных, чтобы наше приложение смогло подключиться к нашей базе данных.

Чтобы максимально разделить интересы вашего приложения, создайте отдельный файл для информации о подключении базы данных с именем db.js. Откройте файл в nano или вашем любимом редакторе:

  1. nano db.js

Во-первых, импортируйте модуль mongoose с помощью функции require:

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

Это позволит вам получить доступ к встроенным методам Mongoose, которые вы будете использовать для создания подключения к вашей базе данных.

Далее добавьте следующие константы для определения информации для URI подключения к Mongo. Хотя использование имени пользователя и пароля не является обязательным, мы добавим их, чтобы с их помощью можно было запрашивать аутентификацию для нашей базы данных. Обязательно замените имя пользователя и пароль, представленные ниже, на ваши собственные. Также вы можете назвать базу данных как-то иначе, чем «^>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() мы указали, что хотим использовать новый парсер URL-адресов Mongo.

Сохраните и закройте файл после завершения редактирования.

В качестве заключительного шага добавьте информацию о подключении базы данных в файл 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 — Создание схем и моделей Mongoose

Нашим следующим шагом будет изучение структуры коллекции sharks, которую будут создавать пользователи в базе данных sharkinfo с помощью ввода данных. Какую структуру должны иметь создаваемые нами документы? Страница информации об акуле в нашем текущем приложении содержит некоторые сведения о разных акулах и их поведении:

Страница информации об акулах

В соответствии с этой темой мы можем попросить пользователей добавлять новых акул с общими данными о них. Эта цель будет определять то, как мы создадим нашу схему.

Чтобы обеспечить отличие ваших схем и моделей от других частей приложения, создайте директорию models в текущей директории проекта:

  1. mkdir models

Далее откройте файл sharks.js для создания вашей схемы и модели:

  1. nano models/sharks.js

Импортируйте модуль mongoose в верхней части файла:

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

Ниже определите объект Schema для использования в качестве основы для вашей схемы акулы:

~/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 с помощью функции model() в Mongoose. Эта модель позволит запрашивать документы из вашей коллекции и выполнять валидацию новых документов. Добавьте следующую строку внизу файла:

~/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, чтобы мы могли использовать его в логике нашего контроллера. Также мы импортируем модуль path для доступа к утилитам, которые позволят нам задать путь к форме, куда пользователи будут вводить данные об акулах.

Добавьте следующие обязательные функции в начало файла:

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

Далее мы напишем последовательность функций, которые мы будем экспортировать в модуль контроллера с помощью сочетания клавиш exports. Эти функции будут включать три задачи, связанные с данными об акулах нашего пользователя:

  • Отправка пользователям формы ввода акулы.
  • Создание новой записи акулы.
  • Отображение акул для пользователей.

Для начала создайте функцию 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, которую мы импортировали. Мы добавили метод console.log для вывода записи акулы в консоль, чтобы убедиться, что наш метод POST работает надлежащим образом, но вы можете пропустить этот шаг, если хотите.

Используя объект newShark, функция create будет вызывать метод model.save() Mongoose для создания нового документа акулы, используя ключ, который вы определили в модели Shark. Эта функция обратного вызова соответствует стандартной схеме обратного вызова Node: 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() Mongoose для возврата акул, которые были добавлены в коллекцию sharks. Она выполняет эту задачу, возвращая объект запроса — в данном случае это все записи в коллекции sharks — в качестве обеспечения, используя функцию exec() Mongoose. В случае ошибки функция обратного вызова будет отправлять ошибку с кодом 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 для сбора и отображения данных

Чтобы наше приложение могло работать с данными пользователя, нам нужно сделать две вещи: сначала мы добавим встроенную функцию межплатформенного ПО Express, urlencoded(), которая позволит нашему приложению парсить вводимые пользователем данные. А затем мы добавим теги шаблона в наши представления, чтобы активировать динамическое взаимодействие с данными пользователя в нашем коде.

Для работы с функцией urlencoded() Express откройте ваш файл 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 мы просматривали эту страницу для определения того, как мы должны записать нашу схему и модель Mongoose:

Страница информации об акулах

Теперь, вместо того, чтобы использовать дизайн с двумя столбцами, мы добавим третий столбец с формой, где пользователи смогут вводить информацию об акулах.

В качестве первого шага укажите размеры 4 для существующих столбцов, чтобы создать три столбца одинакового размера. Обратите внимание, что вам нужно внести эти изменения в двух строках, которые сейчас выглядят следующим образом: <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 с пользовательскими данными об акуле и тегами шаблона 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.

Весь контейнер со всеми тремя столбцами, включая столбец с формой ввода акулы, будет выглядеть следующим образом после завершения этих действий:

~/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, включая информацию о последней добавленной акуле.

Весь контейнер со всеми тремя столбцами, включая столбец с коллекцией 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/routes/index.js
const express = require('express');
const router = express.Router();
const path = require('path');

Далее добавьте следующую функцию router.use, которая загружает промежуточную функцию, которая будет регистрировать запросы маршрутизатора и передавать их на маршрут приложения:

~/node_project/routes/index.js
...

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

Запросы к корню нашего приложения будут направляться сначала сюда, а уже отсюда пользователи будут направляться на начальную страницу нашего приложения согласно маршруту, который мы определим здесь. Добавьте следующий код под функцией router.use для определения маршрута к начальной странице:

~/node_project/routes/index.js
...

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

Когда пользователи будут посещать наше приложение, первым местом, куда мы будем направлять их, будет начальная страница index.html, которую мы разместили в директории views.

Наконец, чтобы сделать эти маршруты доступными в качестве импортируемого модуля в любом месте приложения, добавьте закрывающее выражение в конце файла для экспорта объекта router:

~/node_project/routes/index.js
...

module.exports = router;

Итоговый файл будет выглядеть примерно так:

~/node_project/routes/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

Вверху файла импортируйте объекты express и router:

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

Далее импортируйте модуль с именем sharks, который позволит нам работать с экспортируемыми функциями, определенными с помощью контроллера:

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

Теперь вы можете создавать маршруты с помощью функций index, create и list, определенных в файле контроллера sharks. Каждый маршрут будет ассоциироваться с соответствующим методом HTTP: GET в случае отображения главной страницы с информацией об акулах и возврата списка акул пользователю, и POST в случае создания новой записи акулы:

~/node_project/routes/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/routes/index.js
...

module.exports = router;

Итоговый файл будет выглядеть примерно так:

~/node_project/routes/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 Shark Info (Получить информацию об акулах). Вы увидите следующую информационную страницу с добавленной формой ввода акулы:

Форма информации об акуле

В этой форме добавьте акулу по вашему выбору. В демонстрационных целях мы добавим Megalodon Shark в поле Shark Name (Имя акулы) и Ancient в поле Shark Character (Тип акулы):

Заполненная форма акулы

Нажмите кнопку Submit (Отправить). Вы увидите страницу с информацией об акуле, отображаемая для вас:

Вывод акулы

Также вы увидите вывод в консоли, указывающий, что акула добавлена в вашу коллекцию:

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

Если вы хотите создать новую запись акулы, вернитесь на страницу Sharks и повторите процесс добавления акулы.

Теперь у вас есть рабочее приложение с информацией об акулах, позволяющее пользователям добавить информацию о своих любимых акулах.

Заключение

В этом обучающем руководстве вы создали приложение Node, выполнив интеграцию с базой данных MongoDB и переписав логику приложения с помощью шаблона архитектуры MVC. Это приложение может выступать в качестве хорошей начальной точки для полномасштабного CRUD приложения.

Дополнительную информацию по использованию шаблонов MVC в другом контексте см. в нашей серии о разработке Django или руководстве Создание современного веб-приложения для управления данными клиента с помощью Django и React в Ubuntu 18.04.

Дополнительную информацию о работе с MongoDB см. в нашей библиотеке обучающих материалов для MongoDB.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
Leave a comment


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more