Node.JS, Express и MongoDB Технологии создания веб-приложений


Node.JS, Express и MongoDB

Технологии создания веб-приложений на основе Node, Express и MongoDB

Автор: Владимир Ткаченко

Источник: Обучение в интернет

Продолжение статьи MongoDB Node.JS Driver. Продолжим рассмотрение технологии взаимодействия СУБД MongoDB с приложениями, созданными на JS в среде Node.js, с помощью драйвера MongoDB NodeJS. В этой статье исследуем возможности обмена данными с MongoDB через графический интерфейс пользователя с применением AJAX запросов при помощи jQuery - $.ajax().

В статье изложены технологии и средства создания веб-приложения на основе: HTML5, CSS3, JavaScript, jQuery, DOM, Bootstrap, JSON, AJAX, Node.js, Express и NoSQL (MongoDB). Веб-приложение предназначено для манипулирование данными в системе рассылки СМС сообщений через Интернет.

Для этого создадим веб-сайт или веб-приложение (Node-приложение) с клиентской и серверной частями на языке программирования JS. Обмен данными между клиентской частью (графическим интерфейсом пользователя) и серверной частью приложения Node.js осуществляется с применением AJAX-запросов при помощи jQuery - $.ajax(), а взаимодействие MongoDB с Web-приложением, созданным с помощью веб-фреймворка express на JavaScript в среде Node.js, осуществляется с помощью драйвера MongoDB NodeJS.

Директория для веб-приложения с базой "WSMSdb" и коллекцией "employees"

Создадим для веб-приложения новый каталог, который назовем, W_SMS. В директории W_SMS создадим файл конфигурации package.json, который содержит метаданные для веб-приложения. В каталоге W_SMS установим драйвер mongodb:
npm install mongodb --save

Далее в этом каталоге установим фреймворк express для создания веб-приложения, выполнив команду:
C:\W_SMS>npm install express --save

Затем установим пакет body-parser для обработки запросов JSON:
C:\W_SMS>npm install --save body-parser

В результате выполнения команды «npm» будут загружены модули mongodb, express, body-parser и будет добавлена запись ("mongodb": "^3.1.10", "express": "^4.16.4" и "body-parser": "^1.18.3") в файл "package.json"


{
  "name": "W_SMS",
  "version": "1.0.0",
  "description": "my first W_SMS",
  "dependencies": {
    "body-parser": "^1.18.3",
    "express": "^4.16.4",
    "mongodb": "^3.1.10",
   },
  "scripts": {
    "start": "node server.js"
  },
  "main": "server.js",
  "devDependencies": {},
  "author": "",
  "license": "ISC"
}		        

Далее в каталоге W_SMS создадим файл server.js и директорию public в которой создадим файлы client.js и index.html с помощью которых будут выполняться основные операции CRUD, т.е. операции, выполняемые для создания, чтения, обновления и удаления документов (create, read, update, delete). Проект W_SMS с базой "WSMSdb" и коллекцией "employees", в которую входят документы, включающие в себя набор текстовых полей в формате JSON, предназначен для рассылки SMS сообщений через Интернет.

Cоздания серверной части веб-приложения server.js с применением веб-фреймворка express и драйвера mongodb

Существует множество методов создания Node-приложений для работы с MongoDB, с помощью которых могут быть выполнены операции CRUD. В качестве образца для создания веб-приложения используем файлы app.js и index.html сайта о программировании, в которых для взаимодействия с MongoDB (выполнения операций CRUD) скрипты для обработки запросов с помощью Express объединены в один файл app.js.

Чтобы не отображалось предупреждение "Deprecation Warning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to mongoClient.connect" в метод connect() добавим опцию { useNewUrlParser: true }.
Итак, по аналогии с файлом app.js создадим файл server.js:


// директива use strict.
'use strict';
// Подключаем веб-фреймворк express.
const express = require("express");
// Подключаем модуль body-parser.
const bodyParser = require("body-parser");
// Подключаем официальный драйвер Node.js - mongodb.
const mongoClient = require("mongodb").MongoClient;
// Подключаем объектный идентификатор.
const objectId = require("mongodb").ObjectID;
// Создаем объект приложения. 
const app = express();
// jsonParser превращает строку текста JSON в объект Javascript.
const jsonParser = bodyParser.json();
// Объявляем URL-адрес подключения к WSMSdb.
const url = "mongodb://localhost:27017/WSMSdb";
// Настраиваем статическую файловую папку для маршрута по умолчанию.
app.use(express.static(__dirname + "/public"));
/* Определяем обработчик для маршрута "/api/employees".
 На метод GET-запроса клиентской части к серверной части приложения Node.js по маршруту "/api/employees" осуществляется 
загрузка в таблицу клиентского приложения всех сотрудников из базы данных WSMSdb методом find().
*/ 
app.get("/api/employees", function(req, res) {
	
	// Для подключения приложения Node.js к локальному серверу БД WSMSdb применяем метод connect().
	mongoClient.connect(url,  { useNewUrlParser: true }, function(err, client){
	/* Объекту db присваиваем объект client с методом db(). У объекта client есть метод  client.db(),   
	с помощью которого клиент может осуществлять взаимодействия  с локальным сервером баз данных.
	*/
	const db = client.db("WSMSdb");
    if(err) return console.log(err);
    db.collection("employees").find().toArray(function(err, employees){
	// Определим ответ серверной части для клиентской части приложения Node.js  методом res.send() - отправка ответов различных типов.
	res.send(employees)
	// Определим метод завершения соединения приложения Node.js с базой данных.  
	client.close();
   
        });
    });
});
// На метод GET-запроса к приложению по маршруту "/api/employees/:id" осуществляется  загрузка одного сотрудника с его id из WSMSdb  методом findOne().
app.get("/api/employees/:id", function(req, res){
    var id = new objectId(req.params.id);
	
	mongoClient.connect(url,  { useNewUrlParser: true }, function(err, client){
	    const db = client.db("WSMSdb");
		db.collection("employees").findOne({_id: id}, function(err, employee){
            // Установим статус ответа HTTP, используя response.status().
			if(err) return res.status(400).send();
            res.send(employee);
            client.close();
        });
    });
});
 // На метод POST-запроса к приложению по маршруту "/api/employees", данные о сотруднике добавляются в WSMSdb  методом insertOne().
app.post("/api/employees", jsonParser, function (req, res) {

/* res.sendStatus(statusCode)-устанавливает код состояния HTTP ответа в значение 
statusCode и отправляет его строковое представление в качестве тела ответа.
*/
    if(!req.body) return res.sendStatus(400);
    const employeeName = req.body.name;
    const employeePhone_number = req.body.phone_number;
    const employee = {name: employeeName, phone_number: employeePhone_number};
 
	mongoClient.connect(url, { useNewUrlParser: true }, function(err, client){
    const db = client.db("WSMSdb");
    db.collection("employees").insertOne(employee, function(err, result){
        if(err) return res.status(400).send();
		res.send(employee);	
        client.close();	
        });
    });
});
// На метод запроса DELETE к приложению по маршруту "/api/employees/:id" данные о сотруднике удаляются из WSMSdb  методом findOneAndDelete().
app.delete("/api/employees/:id", function(req, res){
    const id = new objectId(req.params.id);
	
	mongoClient.connect(url, { useNewUrlParser: true }, function(err, client){
    const db = client.db("WSMSdb");
	        db.collection("employees").findOneAndDelete({_id: id}, function(err, result){
            if(err) return res.status(400).send();
            const  employee = result.value;
            res.send(employee);
            client.close();
        });
    });
});
//  На метод PUT-запроса  к приложению по маршруту "/api/employees/" обновляются данные в WSMSdb методом findOneAndUpdate().
app.put("/api/employees", jsonParser, function(req, res){
    if(!req.body) return res.sendStatus(400);
    const id = new objectId(req.body.id);
    const employeeName = req.body.name;
    const employeePhone_number = req.body.phone_number;
	
    mongoClient.connect(url, { useNewUrlParser: true }, function(err, client){
    const db = client.db("WSMSdb"); 
            db.collection("employees").findOneAndUpdate({_id: id}, { $set: {phone_number: employeePhone_number, name: employeeName}},
            {returnOriginal: false },function(err, result){
            if(err) return res.status(400).send();
            const employee = result.value;
            res.send(employee);
            client.close();
        });
    });
});
 
app.listen(3000, function(){
    console.log("Сервер прослушивает входящие подключения к порту: 3000");
});	
			

Взаимодействие MongoDB с Web-приложением, созданным с помощью веб-фреймворка express на JavaScript в среде Node.js, осуществляется с помощью драйвера MongoDB NodeJS

Далее создаем файл графического интерфейса пользователя index.html на основе языка разметки html5, языка таблицы стилей CSS3, языка программирования JS, фреймворка для разработки адаптивных и мобильных web-проектов bootstrap.

Код графического интерфейса пользователя index.html имеет вид:


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>SMS SERVICES</title>
    <link href="css/bootstrap.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">
	<script src="js/jquery-3.1.1.min.js"></script>
</head>
<body>
    <header>
	    <div id="right-header">
     	<br><h1>SMS SERVICES</h1><br><br>
	    </div>
        <nav class="navbar navbar-default">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
						<span class="sr-only">Toggle navigation</span>
						<span class="icon-bar"></span>
						<span class="icon-bar"></span>
						<span class="icon-bar"></span>
					</button>
                </div>
                 <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                    <ul class="nav navbar-nav">
                        <li class="active-link"><a href="index.html">home</a></li>
                        <li class="active-link"><a href="inform.html">messages</a></li>
                        <li class="active-link"><a href="articles.html">employees</a></li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
<div class="content">	
    <div class="container">
        <div class="row">
            <div class="col-lg-12 col-md-12 col-sm-12">
			<div class="panel panel-default">
                        <div class="panel-heading">
                            <h1>EMPLOYEES LIST</h1>
                        </div>
                    <div class="panel-body">
	<form name="employeeForm">
        <input type="hidden" name="id" value="0" />
        <div class="form-group">
            <label for="name">Name:</label>
            <input class="form-control" name="name" />
        </div>
        <div class="form-group">
            <label for="phone_number">Phone:</label>
            <input class="form-control" name="phone_number" />
        </div>
        <div class="panel-body">
            <button type="submit" class="btn btn-sm btn-primary">Submit</button>
            <a id="reset" class="btn btn-sm btn-primary">Reset</a>
        </div>
    </form>
		<div class="panel-body">
			<a href ='' onclick = 'GetEmployees(); return false;' class="btn btn-sm btn-primary">Employees</a>
		</div>
    <table class="table table-condensed table-striped table-bordered">
        <thead><tr><th>Id</th><th>Name</th><th>Phone</th><th></th></tr></thead>
        <tbody>
        </tbody>
    </table>
	<script src="js/client.js"></script>
	
                </div>
            </div>
        </div>
    </div>
</div>
    <footer class="footer">
        <div class="container">
            <div class="panel-footer">
                <p class="pull-left">
                    © 2018, SMS SERVICES
                </p>
            </div>
        </div>
    </footer>
        <script>
        $(".panel-heading>h1").css("color", "#666666");
		$("h3").css("color", "#666666").css("text-align", "left").css("font-size", "1.0em");
		$(".news1>p").css("font-size", "0.90em");
        $("p.pull-left").css("color", "blue");
    </script>
</body>
</html>   

Скриншот графического интерфейса пользователя или веб-страницы index.html, представленный на рис. 1, содержит форму ввода данных (Name, Phone) о сотруднике, которая используется для ввода данных в БД MongoDB (WSMSdb) и обновления данных. Кроме того, интерфейс содержит таблицу, которая предназначена для данных (Id, Name, Phone) о сотрудниках, полученных из БД MongoDB (WSMSdb). В интерфейсе имеется кнопки управления: Submit - для отправки данных из формы в БД; Reset - для сброса данных из формы; Employees - для вызова данных о клиентах из БД и отображения их в таблице веб-страницы.

Интерфейс пользователя для веб-приложения на основе Node, Express и MongoDB
Рис. 1. Скриншот графического интерфейса пользователя, созданного на основе html5, CSS3, JS, bootstrap.

Затем создадим клиентскую часть веб-приложения или скрипт client.js для файла index.html и разместим этот скрипт в директорию js, которая помещена в директорию public.

Создание клиентской части приложения client.js

Клиентская часть веб-приложения client.js создана с применением AJAX-запросов при помощи jQuery - $.ajax() на основе вышеуказанного файла index.html из сайта о программировании:


    // По Get-запросу данные о всех сотрудниках коллекции employees, полученные с серверной части веб-приложения, помещаются в таблицу 
    function GetEmployees() {
		// Метод jQuery ajax ()
	$.ajax({
		// путь к обработчику запроса
        url: "/api/employees",
		// метод передачи данных
        type: "GET",
		// Тип содержимого, используемый при отправке данных на сервер
        contentType: "application/json",
		// функция, которая вызывается в случае удачного завершения запроса к серверу
        success: function (employees) {
                var rows = "";
                    $.each(employees, function (index, employee) {
                       // Добавляются строки с данными в таблицу
                        rows += row(employee);
                    })
                    $("table tbody").append(rows);
                 },
            });
        };
        // Данные об одном сотруднике передаются в форму, где их можно изменить
        function GetEmployee(id) {
            $.ajax({
                url: "/api/employees/"+id,
                type: "GET",
                contentType: "application/json",
                success: function (employee) {
                    var form = document.forms["employeeForm"];
                    form.elements["id"].value = employee._id;
                    form.elements["name"].value = employee.name;
                    form.elements["phone_number"].value = employee.phone_number;
                },
            });
        };
        // Добавление сотрудника в коллекцию employees базы данных WSMSdb
        function CreateEmployee(employeeName, employeePhone_number) {
            $.ajax({
		// путь к обработчику
                url: "api/employees",
                contentType: "application/json",
                method: "POST",
		// JSON.stringify()  сериализует (превращает) объект JS в строку JSON
                data: JSON.stringify({
                    name: employeeName,
                    phone_number: employeePhone_number
                }),
		// функция, которая будет вызвана в случае удачного завершения запроса к серверу
                success: function (employee) {
                    reset();
                    $("table tbody").append(row(employee));
                },
            });
        };
        // Изменение данных о сотруднике
        function EditEmployee(employeeId, employeeName, employeePhone_number) {
            $.ajax({
                url: "api/employees",
                contentType: "application/json",
                method: "PUT",
		// JSON.stringify() - создать строку JSON из объекта
                data: JSON.stringify({
                    id: employeeId,
                    name: employeeName,
                    phone_number: employeePhone_number
                }),
                success: function (employee) {
                    reset();
                    console.log(employee);
                    $("tr[data-rowid='" + employee._id + "']").replaceWith(row(employee));
                },
            });
        };
  
        // Сброс данных из формы
        function reset() {
            var form = document.forms["employeeForm"];
            form.reset();
            form.elements["id"].value = 0;
        };
  
        // Удаление сотрудника из коллекции БД 
        function DeleteEmployee(id) {
            $.ajax({
                url: "api/employees/"+id,
                contentType: "application/json",
                method: "DELETE",
                success: function (employee) {
                    console.log(employee);
                    $("tr[data-rowid='" + employee._id + "']").remove();
                },
            });
        };
        // Создание строки для таблицы
        var row = function (employee) {
            return "" + employee._id + "" +
                   "" + employee.name + " " + employee.phone_number + "" +
                   "Изменить | " +
                    "Удалить";
        }
        // Сброс значений формы
        $("#reset").click(function (e) {
  
            e.preventDefault();
            reset();
        });
  
        // Отправка данных из формы
        $("form").submit(function (e) {
            e.preventDefault();
            var id = this.elements["id"].value;
            var name = this.elements["name"].value;
            var phone_number = this.elements["phone_number"].value;
            if (id == 0)
                CreateEmployee(name, phone_number);
            else
                EditEmployee(id, name, phone_number);
        });
  
        // Ссылка "Изменить"
        $("body").on("click", ".editLink", function () {
            var id = $(this).data("id");
            GetEmployee(id);
        });
        // Ссылку "Удалить"
        $("body").on("click", ".removeLink", function () {
            var id = $(this).data("id");
            DeleteEmployee(id);
        });
             	

После создания клиентской части веб-приложения client.js и помещения ее в директорию public/js подключим скрипт client.js в html-код веб-страницы index.html между тегами <body></body>, в таком виде: <script src="js/client.js"></script>

В командной строке запустим сервер баз данных MongoDB, который находится в папке bin и называется mongod:
C:\mongodb>bin\mongod

Теперь запустим файл server.js на выполнение во второй командной строке, для этого перейдем в каталог W_SMS, в котором он помещено:
C:\W_SMS>node server.js

Введем в адресную строку браузера локальный адрес веб-приложения http://localhost:3000/, в результате чего в окне браузера будет отображаться веб-страница index.html с пустой таблицей данных о сотрудниках и средствами управления базой данных MongoDB (WSMSdb).

Интерфейс пользователя для веб-приложения на основе Node, Express и MongoDB

Рис. 2. Скриншот интерфейса пользователя, в котором отображается пустая таблица данных о сотрудниках и средства управления БД.

Используя средства управления графического интерфейса пользователя, можно выполнять основные операции CRUD:

  • "создание" - (введение в БД данных о сотруднике) осуществляется путем ввода данных в форму и нажатием кнопки "Submit". Данные передаются в БД с применением AJAX запросов при помощи jQuery - $.ajax() без перезагрузки всей веб-страницы. Данные, введенные в базу данных, будут отображаться в таблице веб-страницы, в которую они поступят из БД;
  • "обновление" - изменение данных о сотрудниках в БД, которые отображаются в таблице веб-страницы осуществляется щелчком по ссылке "Изменить". При этом данные о сотруднике передаются в форму, где их можно изменить и для сохранения обновления надо щелкнуть на кнопке "Submit" или отменить, щелкнув на кнопке "Reser";
  • "удаление" - удаление данных о сотрудниках в БД, которые отображаются в таблице веб-страницы осуществляется щелчком по ссылке "Удалить";
  • "чтение" - чтение или загрузка данных о сотрудниках, полученных из БД WSMSdb, в таблицу веб-страницы и отображение данных о клиентах в таблице осуществляется нажатием кнопки "Employees". После щелчка на кнопке "Employees" данные о сотрудниках, хранящихся в базе данных MongoDB (WSMSdb) будут отображаться таблице веб-страницы.

Таким образом, данные о сотрудниках вводятся в БД с помощью формы интерфейса пользователя. Редактирование и удаление данных осуществляется путем загрузки данных в таблицу веб-страницы index.html и выполнения операций CRUD.

На рисунке 3 представлен скриншот веб-страницы после нажатия кнопки "Employees". На веб-странице отображается данные о всех сотрудниках, хранящихся в базе данных MongoDB (WSMSdb).

Интерфейс пользователя для веб-приложения на основе Node, Express и MongoDB с данными о всех сотрудниках, хранящихся в БД
Рис. 3. Скриншот графического интерфейса пользователя с данными о всех сотрудниках, хранящихся в БД.

Теперь, используя средства управления БД (кнопки Submit и Reset, а также ссылки "Изменить" и "Удалить"), можно отредактировать данные о сотрудниках, которые хранятся в базе данных MongoDB (WSMSdb).

В дальнейшем будет рассмотрено хранение данных в облаке mLab или Atlas MongoDB Cloud и взаимодействие облачных БД с приложениями, созданными на JS в среде Node.js.