Node.js: экспресс-маршрут, запрос данных из базы данных и рендеринг в представлении template.hbs. - PullRequest
0 голосов
/ 28 апреля 2018

Я хочу создать приложение Node.js, которое выполняет веб-очистку некоторых сайтов, сохраняет данные в базе данных PostgreSQL, а затем отображает визуализации (в D3.js) этих данных на веб-странице. Я думал о разделении входной части (создание и отображение визуализаций) и внутренней части (выполнение очистки и обновление базы данных в Интернете).

Скелет двух приложений (их два, потому что я делю задачи на два приложения) выглядит следующим образом.

Бэк-приложение (scraper):

  • подключение к БД
  • создание таблиц, если они не существуют
  • скребок данных
  • сохранение данных на БД
  • отключение от БД.

Это фоновое приложение должно запускаться только пару раз в год (для этого я могу настроить файл CRON, если, например, используется Unix).

Приложение переднего плана (viz):

  • подключение к БД
  • запустить сервер, который ожидает на порту 3000 (он мне нужен для визуализации)
  • каждый раз, когда пользователь обновляет страницу (onLoad()), приложение выполняет запрос (SELECT), который получает данные из базы данных. Таким образом, данные всегда обновляются.

Это приложение запускается программистом только один раз (в идеале).

Я создал структуру папок этого типа (я использовал npm init и Express):

project
 |_ scraper
     |_ helpers // contains some useful .js files
          |_ elaborateJson.js
          |_ saveOnDb.js
          |_ utilFunc.js
     |_ node_modules // modules installed using `npm install moduleName --save`
     |_ routes // contains the files that make scraping
          |_ downloaderHome.js
          |_ downloaderWork.js
     |_ services // contains a files concerning the db
             |_ postgreSQLlib.js
     |_ app.js
     |_ package.json
     |_ package-lock.json
 |_ viz
     |_ helpers // // contains some useful .js files
          |_ utilFunc.js
     |_ node_modules // modules installed using `npm install moduleName --save`
     |_ public // contains files for visualizations
          |_ index.handlebars
          |_ script.js
          |_ style.css
     |_ services // contains a file concerning the db
             |_ postgreSQLlib.js
     |_ app.js
     |_ package.json
     |_ package-lock.json

С этой структурой у меня уже есть две проблемы, которые я не знаю, как решить:

1. Файл postgreSQLlib.js (а также utilFunc.js) одинаков как для scraper, так и viz. Как я могу избежать этого дублирования кода?

2. Мне пришлось дважды установить некоторые модули (например, express-handlebars и express) в папки scraper и viz.

Это project/scraper/app.js:

const downloaderHome = require('./routes/downloaderHome.js');
const downloaderWork = require('./routes/downloaderWork.js');
const postgreSQLlib = require('./services/postgreSQLlib.js');
const saveOnDb = require('./helpers/saveOnDb.js');
const utilFunc = require('./helpers/utilFunc.js');
const express = require('express');
const exphbs = require('express-handlebars');

var app = express();

start();

async function start() {
    console.log('\n Connect to db');
    await postgreSQLlib.connect();

    console.log('\n Create tables if they do not exist');
    await postgreSQLlib.createHomeTable();
    await postgreSQLlib.createWorkTable();

    console.log('\n Check if table \'home\' is updated or not');
    if(!await utilFunc.isTableUpdated('home', 6418)) { // 6308
        console.log('\n   Download data for home');
        await downloaderHome.download();
        console.log('\n   Saving data for home on db');
        await saveOnDb.saveHome();
    }   

    console.log('\n Check if table \'work\' is updated or not');
    if(!await utilFunc.isTableUpdated('work', 6804)) {
        console.log('\n   Download data for work');
        await downloaderWork.download();
        console.log('\n   Saving data for work on db');
        await saveOnDb.saveWork();
    }

    console.log('\n Disconnect from db');
    await postgreSQLlib.disconnect();
}

Это project/viz/app.js:

const postgreSQLlib = require('./services/postgreSQLlib.js');
const utilFunc = require('./helpers/utilFunc.js');
const express = require('express');
const exphbs = require('express-handlebars');
const http = require('http');

var app = express();

var response;
var callback;

start();

async function start() {
    console.log('\n Connect to db');
    await postgreSQLlib.connect();

    // how do I check when page is refreshed?!
    http.get({
            hostname: 'localhost',
            port: 3000,
            path: '/',
            agent: false
        }, callback);

    callback = function(res) {
        response = res;
        console.log(response); // here response will return an object
        console.log('refresh callback');
    }

    console.log(response);
    console.log('refresh');

    ///////////////////////////////////////////////
    // How do I check the disconnection from the db? 
    // If I disconnect now, the visualizations are no longer work. 
    // So when do I get disconnected? 
    // Create problems leaving the connection to the active db?
    ///////////////////////////////////////////////
    //console.log('\n Disconnect from db');
    //await postgreSQLlib.disconnect();
}

Первое приложение (project/scraper/app.js) работает отлично.

Второе приложение (project/viz/app.js) нет. Я хотел бы, чтобы вы сделали это:

  • подключение к БД [сделано. Это работает]
  • запустить сервер, ожидающий на порту 3000 (он мне нужен для визуализации) [как мне это сделать? Посмотрите вниз (*) ]
  • каждый раз, когда пользователь обновляет страницу (onLoad()), приложение делает запрос (SELECT), который получает данные из базы данных [как мне это сделать?]

(*) Я думал о чем-то вроде этого:

async function start() {
    console.log('\n Connect to db');
    await postgreSQLlib.connect();

    console.log('\n Get data from db');
    var dataHome = await postgreSQLlib.getTableHome();
    var dataWork = await postgreSQLlib.getTableWork();

    //console.log('\n Connect to my server');
    pageLoad(dataHome, dataWork); 
}

function pageLoad(dataHome, dataWork) {
    var hbs = exphbs.create({
        helpers: {
            getDataHome: function() { 
                return JSON.stringify(dataHome); 
            },
            getDataWork: function() { 
                return JSON.stringify(dataWork); 
            }
        }
    });

    app.engine('handlebars', hbs.engine);
    app.set('view engine', 'handlebars');

    app.get('/', function(req, res, next) {
        res.render('index', { // index is html filename
            showTitle: true,
        });
    });
    console.log('Go to http://localhost:3000/ to see visualizations');
    app.listen(3000);
}

Где dataHome и dataWork - два объекта, которые содержат данные, загруженные из базы данных с использованием запроса SELECT. Но при этом данные удаляются только один раз, а не каждый раз, когда пользователь обновляет страницу.

Помощь будет принята с благодарностью. Спасибо!

EDIT

Не могли бы вы быть более точным? Я пытался сделать это, но это не работает:

проект / именно / app.js :

const postgreSQLlib = require('../shared_libs/postgreSQLlib.js');
const express = require('express');

var app = express();

start();
async function start() {
    console.log('Connect to db');
    await postgreSQLlib.connect();

    app.get('/', fetchFreshData);
}

async function fetchFreshData(req, res) {
    // download data from db
    var dataHome = await postgreSQLlib.getTableHome();
    var dataWork = await postgreSQLlib.getTableWork();
    // fill this JSON using the results
    var viewData = {dataHome, dataWork};
    // pass data to view
    res.render('index', viewData);
}

проект \ а именно \ вид \ index.handlebars

<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>Map</title>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <link rel='stylesheet' type='text/css' href='/style.css' media='screen'/>
    </head>
    <body>
        <div id='example'></div>
    </body>
    <script src='/script.js'></script>
</html>

проект \ а именно \ вид \ script.js

console.log('viewData:', viewData);

Где я не прав?

РЕДАКТИРОВАТЬ 2

Хорошо, я снова изменяю код viz/app.js:

const postgreSQLlib = require('../shared_libs/postgreSQLlib.js');
const express = require('express');
const exphbs = require('express-handlebars');

var app = express();

start();

async function start() {
    await postgreSQLlib.connect();

    var hbs = Handlebars.registerHelper('json', function(context) {
        return JSON.stringify(context);
    });
    app.engine('handlebars', hbs.engine);
    app.set('view engine', 'handlebars');
    app.get('/', fetchFreshData);
    console.log('Go to http://localhost:3000/ to see data');
    app.listen(3000);
}

async function fetchFreshData(req, res) {
    // download data from db
    var dataHome = await postgreSQLlib.getTableHome();
    var dataWork = await postgreSQLlib.getTableWork();
    // fill this JSON using the results
    var viewData = {}; 
    viewData.timestamp = Date.now();
    viewData.entries = dataHome;
    // pass data to view
    res.render('index', viewData);
}

Когда я запускаю приложение, ошибок нет, но если я подключаюсь к http://localhost:3000/,, браузер сообщает мне, что я не могу зайти на сайт. Я чувствую себя немного глупо ...

РЕДАКТИРОВАТЬ 3

Если я правильно понимаю ваш код, в вашем коде есть (отвлекающая) ошибка. В returnOBJ() вместо res.render('index', viewData); должно быть res.render('obj', viewData); (относится к файлу obj.hbs). Правильно?

Я изменяю файл index.hbs следующим образом:

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>Index</title>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <link rel='stylesheet' type='text/css' href='/style.css' media='screen'/>
    </head>
    <body>
        <h1>INDEX<small>{{timestamp}}</small></h1>
    </body>
    <script> 
        // add global variables in the .hbs file 
        window.viewData_dataWork = {{ json entries }}
        console.log(window.viewData);
    </script>
    <script src='/script.js'></script>
</html>

Но я получаю:

(node:207156) UnhandledPromiseRejectionWarning: Error: callback function required
    at Function.engine (C:\...\node_modules\express\lib\application.js:295:11)
    at start (C:\...\viz\app.js:20:6)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:182:7)
(node:207156) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:207156) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Я тоже не понимаю этот кусок кода.

app.set('view engine', 'hbs');
app.engine('hbs', hbs.__express);
hbs.registerHelper('json', function(context) {
    return JSON.stringify(context);
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');

Почему вы звоните app.set('view engine', ...) два раза с разными значениями?

РЕДАКТИРОВАТЬ 4

Я еще больше упростил код:

/ а именно / app.js

const postgreSQLlib = require(__dirname + './../shared_libs/services/postgreSQLlib.js');
const express = require('express');
const hbs = require('hbs');

var app = express();

// Server initiator
async function start() {
    await postgreSQLlib.connect();

    // hbs
    app.set('views', '' + __dirname + '/views');
    app.set('view engine', 'hbs');
    app.engine('hbs', hbs.__express);
    hbs.registerHelper('json', function(context) {
        return JSON.stringify(context);
    });
    app.engine('handlebars', hbs.engine);
    app.set('view engine', 'handlebars');

    // router
    app.get('/', testMe);

    console.log('Go to http://localhost:3000/ to see data');
    app.listen(3000);
}

// Your section with fresh data has been populated properly
async function testMe(req, res) {
    console.log('testMe');
    // fill this JSON using the results
    var viewData = {}; 
    viewData.data = 'this string';
    // pass data to view
    res.render('test', viewData);
}

// start the server
start();

/ ВИЗ / просмотров / test.hbs

<html>
    <head>
        <title>Server test</title>
    </head>
    <body>
        {{data}}
    </body>
</html>

Затем в командной строке я иду на project/viz и набираю node app.js + enter. Процесс начинается и ждет: ошибок нет. Когда я иду на http://localhost:3000/, но я получаю Ошибка подключения .

Я схожу с ума.

РЕДАКТИРОВАТЬ 5

Проблема была не в connect и не в функциях, которые сделали выбор, поэтому я немного упростил код. и теперь это работает почти!

Вот код.

а именно / app.js

const postgreSQLlib = require(__dirname + './../shared_libs/services/postgreSQLlib.js');
const express = require('express'); 
var app = express()
const hbs = require('hbs');
const webapp_opts = {"port":3000};

Initialize();

//.: Setup & Start Server
async function Initialize(){
    await postgreSQLlib.connect();

    console.log("[~] starting ...")
    //:[HBS]:Setup
    app.set('view engine', 'hbs'); 
    app.engine('hbs', hbs.__express)
    app.set('views', "" + __dirname + "/views")
    //:[HBS]:Helpers
    hbs.registerHelper('json', function(context) {
        return JSON.stringify(context);
    })
    //:[EXPRESS]:Router.Paths
    app.get("/", IndexPathFunction);
    // app.get("/script.js", scriptFile); <-- for script.js file

    //:[EXPRESS]:Start 
    app.listen(webapp_opts.port,()=>{
        console.log("[i] ready & listening","\n    http://localhost:"+webapp_opts.port+"/")
    })
}

/*async function scriptFile(req, res) { <-- for script.js file
    console.log('\nscriptFile');
    var viewData = {}; 
    viewData.number = 50;
    console.log('viewData:', viewData);
    res.render('script.js', viewData);
}*/

//.: Router Function : "/"
async function IndexPathFunction(req,res){
    var viewData = {}; 
    viewData.timestamp = Date.now();
    viewData.exJson = [{color: 'red', year: '1955'}, {color: 'blue', year: '2000'}, {color: 'yellow', year: '2013'}]; 
    viewData.exString = 'example of string'; 
    console.log('viewData:', viewData);
    res.render('index', viewData);
}

ВИЗ / просмотров / index.hbs

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>Index</title>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <link rel='stylesheet' type='text/css' href='/style.css' media='screen'/>
    </head>
    <body>
        <h1>INDEX timestamp: <small>{{timestamp}}</small></h1>
    </body>
    <script> 
        viewData = {}; 
        console.log('viewData:', viewData);
        viewData.exJson = JSON.parse('{{ json exJson }}'.replace(/&quot;/g, '"').replace(/&lt;/, ''));
        viewData.timestamp = {{timestamp}}; // doesn't work
        viewData.exString = {{ exString }}; // doesn't work
        console.log('viewData.exJson:', viewData.exJson);
        console.log('viewData.timestamp:', viewData.timestamp);
        console.log('viewData.exString:', viewData.exString);
    </script>
    <!--<script src='/script.js'></script>-->
</html>

Проблема в том, чтобы получить тип данных, который не является json. Например, это дает мне ошибку, когда я пытаюсь напечатать метку времени и exString. Почему?

Кроме того, я бы хотел немного очистить код и поместить часть javascript в файл script.js, который вызывается index.hbs с использованием <script src='/script.js'></script>.

РЕДАКТИРОВАТЬ 6

Я нашел этот урок , который был очень полезен для меня.

Я отредактировал файл index.hbs, добавив файл css, изображение и скрипт (он содержит только console.log('here');, но идея состоит в том, чтобы поместить в script.js переменную viewData).

проекта / а именно / просмотров / index.hbs

<html lang='en'>
    <head>
        <meta charset='utf-8'>
        <title>Index</title>
        <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
        <link href="/css/style.css" rel="stylesheet">
    </head>
    <body>
        <img src="/images/logo.png"/>
        <h1>timestamp: <small>{{timestamp}}</small></h1>
        <h2>Welcome in index.hbs</h2>
    </body>
    <script> 
        viewData = {}; 
        console.log('viewData:', viewData);
        viewData.exJson = JSON.parse('{{json exJson }}'.replace(/&quot;/g, '"').replace(/&lt;/, ''));
        viewData.timestamp = {{timestamp}};
        viewData.exString = '{{exString}}'; 
        console.log('viewData.exJson:', viewData.exJson);
        console.log('viewData.timestamp:', viewData.timestamp);
        console.log('viewData.exString:', viewData.exString);
    </script>
    <link href='/script/script.js' rel='script'>
</html>

Структура моих файлов:

project
    |_ node_modules
    |_ scraper
    |_ shared_libs
    |_ viz  
        |_ app.js 
        |_ public
            |_ css
                |_ style.css
            |_ images
                |_ logo.png
            |_ script
                |_ script.js
        |_ views
            |_ index.hbs

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

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

1 Ответ

0 голосов
/ 01 мая 2018

Решение для общего (пользовательского) кода:

С этой структурой у меня уже есть две проблемы, которые я не знаю, как решить:

  1. файл postgreSQLlib.js (а также utilFunc.js) одинаков как для scraper , так и , а именно . Как я могу избежать этого дублирования кода?

Вы уже используете require, поэтому переместите файлы из:

project/scraper/services/postgreSQLlib.js
project/viz/services/postgreSQLlib.js

во вновь созданный каталог в корневом каталоге проектов

project
 |_ shared_libs
 |_ scraper
 |_ viz

(в этом примере я использовал shared_libs, вы можете назвать его как хотите)

project/shared_libs/postgreSQLlib.js

Тогда из кода:

const postgreSQLlib = require(__dirname+"/../shared_libs/postgreSQLlib.js");

Таким образом, вам не нужно хранить код в 2 разных файлах в 2 местах


Решение для shared node_modules:

То же самое относится к node_modules просто объедините ваши текущие (каталоги node_modules)

project/scraper/node_modules
project/viz/node_modules

в папку в корне каталога project

project/node_modules

Тогда мои рекомендации:

  1. удалить старые внутри (project/scraper & project/viz)
  2. С этого момента используйте npm i <module> --save из каталога project

Оба project/scraper & project/viz будут использовать project/node_modules без необходимости дублировать целые библиотеки ...


Решение для project/viz/app.js

Если вы хотите извлекать данные из БД по каждому GET запросу

Затем вы должны включить выборку данных из логики DB внутри запроса:

app.get('/',FetchFreshData)

Функция будет содержать выборку и конструировать viewData для hbs, которые будут отображаться со свежими данными, указанными в разметке .hbs

function FetchFreshData(req,res){
 /* add your SELECT here */
 var viewData = {} //fill this JSON using the results
 res.render('index',viewData)
}

Логично, что каждый раз, когда вы выполняете GET по маршруту "/", вы запускаете QUERY и получаете "визуализацию" со свежими данными.


РЕДАКТИРОВАТЬ: расширение ответа

Прежде всего, я бы предложил вам немного глубже понять рули (hbs).

Если вы хотите использовать данные в сценарии, вам нужно будет зарегистрировать помощника на стороне сервера, который отображает данные по мере необходимости.

Handlebars.registerHelper('json',function(context){
 return JSON.stringify(context)
})

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

function FetchFreshData(req,res){
     /* add your SELECT here */
     var viewData = {} //fill this JSON using the results
     viewData.timestamp = Date.now()
     viewData.entries = dataHome
     res.render('index',viewData)
    }

Дал бы нам (пример):

{
 "timestamp":"1525182734",
 "entries":[
   {"name":"Entry 1"},
   {"name":"Entry 2"},
   {"name":"Entry 3"}
 ]
}

Теперь остановлюсь на вашем шаблоне (.hbs):

<html lang='en'>
 <head>
  <meta charset='utf-8'>
  <title>Map</title>
  <script src='https://d3js.org/d3.v5.js' charset='utf-8'></script>
  <link rel='stylesheet' type='text/css' href='/style.css' media='screen'/>
 </head><body>
  <h1>MAP<small>{{timestamp}}</small></h1>
  <div id='example'>
  {{#if entries}}
   <ul>
    {{#each entries}}
     <li> this.name </li>
    {{/each}}
   </ul>
  {{else}} No content... {{/if}}
  </div>
 </body>
    <script> 
     //Add global variables in the .hbs file 
     window.viewData_entries = {{ json entries }}
    </script>
    <script src='/script.js'></script>
</html>

Он будет использовать «ключи» объекта JSON (viewData) получить доступ к данным и визуализировать представление ...


РЕДАКТИРОВАТЬ 2: Попробуйте что-нибудь простое

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

    const postgreSQLlib = require('../shared_libs/postgreSQLlib.js');
    const express = require('express');
    const hbs = require('hbs')
    var app = express();
    //:Server Initiator
    async function start() {
        await postgreSQLlib.connect();
        //:HBS:
        app.set('views', "" + __dirname + "/views");
        app.set('view engine', 'hbs');
        app.engine('hbs', hbs.__express);
        hbs.registerHelper('json',function(context){return JSON.stringify(context)});
        //:Router:
        app.get('/', fetchFreshData);
        app.get('/timestamp', returnTimestamp);
        app.get('/obj', returnOBJ);
        console.log('Go to http://localhost:3000/ to see data');
        app.listen(3000);
    }
    //:Your section with fresh data has been populated properly
    async function fetchFreshData(req, res) {
        var viewData = {}; 
        viewData.timestamp = Date.now();
        viewData.dataWork = await postgreSQLlib.getTableWork();
        viewData.dataHome = await postgreSQLlib.getTableHome();
        // pass data to view
        res.render('index', viewData);
    }
     /*
        The index.hbs I posted earlier wont work anymore, since the   "entries" key doesnt exist now... Try to understand the template  engine with the following 2 examples below
     */

    //:Simple Timestamp EXAMPLE
    function returnTimestamp(req, res) {
        var viewData = {}; 
        viewData.timestamp = Date.now();
        // pass data to view
        res.render('timestamp_example', viewData);
    }
    /* This would be timestamp_example.hbs :
    <html><head><title>Server Timestamp</title></head><body>{{timestamp}}</body></html>
    */

    //:Simple JSON EXAMPLE
    function returnOBJ(req, res) {
        var viewData = {}; 
        viewData.OBJ = {"key":"value"};
        // pass data to view
        res.render('json_example', viewData);
    }
    /* This would be json_example.hbs :
    <html><head><title>Server Object</title></head><body>Page will alert "{{OBJ.key}}"<script>var OBJ = {{json OBJ}}; alert(OBJ.key);</script></body></html>
    */
    //start the server :
    start()

Помните, что вам нужно добавить новые представления для путей /timestamp и /obj, ниже я добавил прокомментированный пример для каждой из функций сервера.

----------

РЕДАКТИРОВАТЬ 3: простая демонстрация с обратными вызовами

 const express = require('express'); var app = express()
    const hbs = require('hbs')
    const webapp_opts = {"port":3000}
    //.: Setup & Start Server
    function Initialize(){
     console.log("[~] starting ...")
        //:[HBS]:Setup
     app.set('view engine', 'hbs'); app.engine('hbs', hbs.__express)
     app.set('views', "" + __dirname + "/views")
        //:[HBS]:Helpers
     hbs.registerHelper('json',function(context){return JSON.stringify(context)})
        //:[EXPRESS]:Router.Paths
     app.get("/",IndexPathFunction)
     app.get("/debug",(req,res)=>{
      console.log("[GET]:/debug");  res.send("ok")
     })
        //:[EXPRESS]:Start 
     app.listen(webapp_opts.port,()=>{
      console.log("[i] ready & listening","\n    http://localhost:"+webapp_opts.port+"/")
     })
    }
    //.: Router Function : "/"
    function IndexPathFunction(req,res){
     DBQuery((query_error,query_results)=>{
      if(query_error){console.log("[!] DBQuery @ path : '/'\n",query_error.stack)}
      else{
       console.log("[+] DBResults :",query_results)
       res.render("index",{data:query_results})
       /*or*/// var viewData = {}; viewData.data=query_results; res.render("index",viewData)
      }
     })
    }
    //:[DB]:Example Query using callback method
    function DBQuery(callback_function){
     console.log("[>] DBQuery")
     pool.connect((err,client)=>{
      if (err) throw err
      client.query('SELECT * FROM whatever',(err,res)=>{
        client.release()
        callback_function(err,res)
      })
     })
    }
    //------------------------------------
    /* We can Initialize() the webapp 
     once we know the DB is accesible : */
    const pg = require('pg')
    const db_opts = {
      "user":"dbuser","password":"secretpassword",
      "host":"database.server.com", "port":3211,
      "database":"mydb"
    })
    var pool = new pg.Pool(db_opts);
    pool.on('error',(err,client)=>{
      console.error('Unexpected error on idle client', err); process.exit(-1)
    })
    pool.connect((err,client,done)=>{
      if(err){console.log("[!] DB Connection Error",err)}
      else{console.log("[+] DB Connected"); client.release(); Initialize() }
    })

Помните, что ключ к пониманию того, что происходит не так, - это контроль потока и наращивание от мелких деталей к большим. Вы должны прочитать: https://node -postgres.com / , особенно эта часть, если вы хотите использовать Экспресс с асинхронностью / ожиданием

В любом случае, этот новый отредактированный раздел должен дать вам некоторое представление о создании минимальной рабочей версии. ;)

...