JavaScript >> Javascript 文檔 >  >> Node.js

將 PostgreSQL 數據庫添加到 Heroku 上的 Node.js 應用程序

簡介

Heroku 是一個支持 Node.js 應用程序的託管服務。它易於使用,並且可以通過附加組件擴展其功能。有各種附加組件,包括消息傳遞/隊列、日誌記錄、指標,當然還有數據存儲。數據存儲插件支持流行的數據庫,如 PostgreSQL、Redis 和 DynamoDB。

在本教程中,我們將向縮短 URL 的 Node 應用程序添加 PostgreSQL 數據庫。然後我們將應用程序部署到 Heroku 並設置 PostgreSQL 插件。

PostgreSQL

如果你還沒有它,你需要在你的機器上安裝 Postgres。根據您的操作系統,有幾種不同的安裝方法。訪問 PostgreSQL 下載頁面了解更多信息。

安裝 PostgreSQL 後,我們可以為 URL 縮短應用程序創建一個數據庫:

$ psql
psql (11.6)
Type "help" for help.

tomkadwill=#

然後使用 CREATE DATABASE SQL命令:

tomkadwill=# CREATE DATABASE urlshortener_development;
CREATE DATABASE
tomkadwill=# \l
                                         List of databases
            Name          |   Owner    | Encoding |   Collate   |    Ctype    |   Access privileges
--------------------------+------------+----------+-------------+-------------+-----------------------
 urlshortener_development | tomkadwill | UTF8     | en_US.UTF-8 | en_US.UTF-8 |

這裡我們創建一個名為 urlshortener_development 的數據庫 然後使用 \l 打印系統中所有 PostgreSQL 數據庫的列表。

我們的新數據庫 urlshortener_development 在那裡,所以我們知道它已成功創建。另外,請注意數據庫所有者,因為我們稍後會需要它(你的和我的不同)。

將 Postgres 集成到節點應用中

我們將要處理的 Node 應用程序相當簡單。如果你想從頭開始構建它,你可以按照我們的指南,將 Node.js 應用程序部署到 Heroku,或者你可以從 GitHub 下載它。

Express 應用程序邏輯都在 app.js 內部 :

const express = require('express');
const app = express();
const path = require('path');
const port = process.env.PORT || 3000;
const urlShortener = require('node-url-shortener');

const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.urlencoded());

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

app.post('/url', function(req, res) {
  const url = req.body.url

  urlShortener.short(url, function(err, shortUrl){
    res.send(shortUrl);
  });
});

app.listen(port, () => console.log(`url-shortener listening on port ${port}!`));

您可以通過 npm start 運行應用程序 .啟動後,瀏覽到 localhost:3000,您應該會看到主頁:

計劃是更新 app.js 以便它將每個 URL 和縮短的 URL 存儲在 DB 表中,然後在 UI 上顯示最後 5 個結果。

我們需要做的第一件事是安裝一個 ORM(對象關係映射器)庫。直接與 PostgreSQL 交互很困難,因為我們必須編寫自己的原始 SQL 查詢。

ORM 允許我們通過更簡單的 API 調用與數據庫進行交互。請注意,使用 ORM 有一些缺點,但我不會在本教程中介紹它們。

Node 有許多不同的 ORM 庫,在這種情況下,我們將使用 Sequelize:

$ npm install --save sequelize
$ npm install --save pg pg-hstore

第一個命令安裝Sequelize 第二個安裝 Node.js 的 PostgreSQL 驅動程序。 Sequelize 支持多個數據庫,所以我們需要指定使用哪一個並提供 Node 驅動程序。

遷移

安裝和配置 Sequelize 後,我們可以考慮數據庫結構。我們只需要一些簡單的東西,一個包含 3 列的表:唯一 ID、原始 URL 和縮短的 URL。

我們可以手動創建新的數據庫表,但這會使部署變得痛苦。我們必須記住我們的查詢並在每個環境中運行它們。

處理數據庫更改的更好方法是通過遷移,這是在應用程序內部編寫數據庫更改的地方。幸運的是,Sequelize 支持開箱即用的遷移。讓我們編寫一個遷移來為 URL 創建一個表。

首先,我們將安裝 Sequelize CLI,它允許我們運行遷移:

$ npm install --save sequelize-cli

接下來我們將初始化 Sequelize:

$ npx sequelize-cli init

這將創建一個 config/config.json 文件和 models , migrations , 和 seeders 目錄。

之後,我們需要修改config.json 文件,以便它可以連接到我們的 PostgreSQL 數據庫:

{
  "development": {
    "username": "tomkadwill",
    "password": "password",
    "database": "urlshortener_development",
    "host": "localhost",
    "dialect": "postgres",
    "operatorsAliases": false
  }
}

文件完成後,讓我們使用 Sequelize CLI 生成遷移。在這裡,我們將通過 attributes 定義我們的字段 旗幟。我們不會包含 id 字段,因為它是自動添加的:

$ npx sequelize-cli model:generate --name Url --attributes url:string,shortUrl:string

這將創建一個如下所示的遷移文件:

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Urls', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      url: {
        type: Sequelize.STRING
      },
      shortUrl: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('Urls');
  }
};

遷移包含 updown 功能。 up 用於向前移動數據庫和down 用於回滾。

在這種情況下 up 創建一個 Urls 有 5 個字段的表。它有 urlshortUrl 字段,以及 id , createdAt , 和 updatedAt ,默認添加。

down 遷移只會刪除 Urls 表。

最後,讓我們運行遷移:

$ npx sequelize-cli db:migrate

運行後,我們可以直接查詢數據庫以檢查一切是否正常:

$ psql -p 5432 "urlshortener_development"
psql (11.6)
Type "help" for help.

urlshortener_development=# \dt
              List of relations
 Schema |     Name      | Type  |   Owner
--------+---------------+-------+------------
 public | SequelizeMeta | table | tomkadwill
 public | Urls          | table | tomkadwill
(2 rows)

urlshortener_development=# \d "Urls"
                                       Table "public.Urls"
  Column   |           Type           | Collation | Nullable |              Default
-----------+--------------------------+-----------+----------+------------------------------------
 id        | integer                  |           | not null | nextval('"Urls_id_seq"'::regclass)
 url       | character varying(255)   |           |          |
 shortUrl  | character varying(255)   |           |          |
 createdAt | timestamp with time zone |           | not null |
 updatedAt | timestamp with time zone |           | not null |
Indexes:
    "Urls_pkey" PRIMARY KEY, btree (id)

如您所見,有兩個數據庫表:SequelizeMetaUrls .如果我們檢查 Urls ,預期的字段就在那裡。

保存網址

現在我們已經配置了 PostgreSQL,並且我們已經創建了一個具有正確結構的數據庫表,下一步是更新我們的應用程序,以便它將 URL 保存到數據庫中。回想一下 npx sequelize-cli model:generate 創建了一個模型文件,我們將使用它來將 URL 保存到數據庫中。

首先我們需要將模型導入到 app.js , 通過要求 models/index.js

const db = require('./models/index.js');

models/index.js 文件由 Sequelize 生成,其目的是包含所有模型文件。

接下來,我們需要更新 post 路由,以便它創建一個數據庫記錄。我們可以使用 findOrCreate() 函數使每個 URL 只有一個唯一的數據庫條目:

app.post('/url', function(req, res) {
  const url = req.body.url

  urlShortener.short(url, function(err, shortUrl) {
    db.Url.findOrCreate({where: {url: url, shortUrl: shortUrl}})
    .then(([urlObj, created]) => {
      res.send(shortUrl)
    });
  });
});

db.Url.findOrCreate() 被調用時,它會嘗試查找與用戶提供的 url 匹配的記錄 並生成 shortUrl .如果找到,則 Sequelize 什麼都不做,否則,它會創建一個新記錄。

在 UI 中顯示 URL

為了用戶友好,讓我們更新應用程序以顯示最後 5 個持久 URL。

為此,我們將添加一個模板引擎,以便 Express 可以動態呈現 URL。有許多可用的模板引擎,但在這種情況下,我們將使用 Express Handlebars:

$ npm install --save express-handlebars

安裝包後我們可以將它添加到 app.js

const exphbs = require('express-handlebars');

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

接下來,我們需要更改應用程序目錄結構。 express-handlebars 假設視圖位於 views 目錄。它還假設我們有一個 views/layouts/main.handlebars 文件:

免費電子書:Git Essentials

查看我們的 Git 學習實踐指南,其中包含最佳實踐、行業認可的標準以及隨附的備忘單。停止谷歌搜索 Git 命令並真正學習 它!

.
├── app.js
└── views
    ├── index.handlebars
    └── layouts
        └── main.handlebars

所以,讓我們移動並重命名 index.html 文件:

$ mv index.html views/index.handlebars

最後,讓我們製作一個佈局文件,views/layouts/main.handlebars

<html>
<head>
    <title>Url Shortener</title>
</head>
<body>
    {{{body}}}
</body>
</html>

模板文件的加載有一定的順序:express-handlebars 將呈現 views/layouts/main.handlebars 然後呈現 views/index.handlebars {{{body}}} 內 標記。

現在我們有了正確的目錄結構,讓我們添加一些 HTML 代碼到 index.handlebars 動態顯示網址:

<ul>
  {{#each urlObjs}}
  <li>{{this.url}} -- <b>{{this.shortUrl}}</b></li>
  {{/each}}
</ul>

這裡我們使用 Handlebars 的 each helper 遍歷每個 URL 對象並顯示原始 URL 和短 URL。

我們需要做的最後一件事是更新 GET app.js 中的路線 將 URL 傳遞到視圖中:

app.get('/', function(req, res) {
  db.Url.findAll({order: [['createdAt', 'DESC']], limit: 5})
  .then(urlObjs => {
    res.render('index', {
      urlObjs: urlObjs
    });
  });
});

讓我們來看看這裡發生了什麼。當/ 被請求,Sequelize 查詢 Urls 桌子。查詢按 createdAt 排序 並且限制為 5 個,這樣可以確保只返回最近的 5 個結果。

查詢結果傳入res.render 作為局部變量urlObjs , 將被模板使用。

渲染出來的頁面是這樣的:

有問題可以到 GitHub 下載完整的代碼。

將應用部署到 Heroku

現在我們已經在本地運行了應用程序,本節將介紹如何讓它在 Heroku 上運行,以及如何在它運行後將數據庫連接到它。

首先,讓我們將所有更改部署到 Heroku:

$ git push heroku master

有關部署到 Heroku 的詳細指南,請參閱將 Node.js 應用程序部署到 Heroku。

連接數據庫

添加數據庫並不難,只需要一個命令行:

$ heroku addons:create heroku-postgresql:hobby-dev

此命令為 Heroku 創建 PostgreSQL 插件並設置一個名為 DATABASE_URL 的環境變量 - 我們只需要通過更新配置文件來告訴 Sequelize 使用它:

{
  "development": {
    "username": "tomkadwill",
    "password": "password",
    "database": "urlshortener_development",
    "host": "localhost",
    "dialect": "postgres",
    "operatorsAliases": false
  },
  "production": {
    "username": "tomkadwill",
    "password": "password",
    "database": "urlshortener_production",
    "host": "localhost",
    "dialect": "postgres",
    "operatorsAliases": false,
    "use_env_variable": "DATABASE_URL"
  }
}

這裡我們為生產添加了一個新的配置部分,除了數據庫名稱和 use_env_variable 之外,它與開發相同 字段。

Sequelize 使用 use_env_variable 獲取用於連接數據庫的環境變量名稱。

Heroku 有 NODE_ENV 默認設置為“生產”,這意味著它將尋找生產配置。讓我們提交並推送到 Heroku。

接下來,我們需要使用 sequelize db:migrate 在 Heroku 上運行遷移 :

$ heroku run bash
Running bash on ⬢ nameful-wolf-12818... up, run.5074 (Free)
~ $ sequelize db:migrate

如果我們之前沒有創建遷移,我們現在將手動運行腳本。

此時,應用程序應該可以在瀏覽器中運行。

管理 Heroku 數據庫

您可能需要在某些時候查詢或修改您的生產數據庫。例如,您可能需要查詢一些數據來幫助診斷錯誤,或者您可能需要修改一些用戶數據。讓我們看看如何做到這一點。

運行 Sequelize 遷移任務

您需要知道的第一件事是如何在 Heroku 上運行 Sequelize 遷移。這是查看可用命令列表的方法:

$ heroku run bash
Running bash on ⬢ nameful-wolf-12818... up, run.1435 (Free)
~ $ sequelize

這些是一些最有用的:

  • sequelize db:migrate:undo :回滾單個遷移
  • sequelize db:migrate:undo:all :回滾所有遷移。有效地恢復到干淨的數據庫
  • sequelize db:migrate:status :檢查您的應用程序正在進行哪個遷移
在控制台中使用 Sequelize 模型

除了 CLI 任務,我們還可以直接在 Node 控制台中使用 Sequelize 模型:

$ heroku run bash
~ $ node
Welcome to Node.js v12.14.0.
Type ".help" for more information.
>

下面是一些可以在 Node 控制台中運行的代碼示例。您可能會注意到它們與 Node REPL 相似。

按 ID 查詢單個 URL:

db.Url.findByPk(1).then(url => {
  console.log(
    url.get({plain: true})
  );
});

查詢所有url:

db.Url.findAll().then(urls => {
  urls.map(url => {
    console.log(
      url.get({plain: true})
    );
  });
});

插入 URL 記錄:

db.Url.create({url: 'https://stackabuse.com/deploying-a-node-js-app-to-heroku', shortUrl: 'https://is.gd/56bEH3'});

通過 ID 查詢 URL 並更新:

db.Url.findByPk(1).then(url => {
  url.shortUrl = 'example.com';
  url.save();
});

按ID查詢URL並刪除:

db.Url.findByPk(1).then(url => {
  url.destroy();
});

結論

有許多附加組件可用於擴展 Heroku。 Heroku Postgres 就是其中一個插件,它允許您輕鬆設置數據庫來存儲應用程序數據。

我們擴展了一個簡單的 Node 和 Express 應用程序,以便它將 URL 存儲在 Heroku 上的 Postgres 數據庫中。


Tutorial JavaScript 教程
  1. JS正則表達式匹配括號之間的數字

  2. 此鏈接中的“消息隊列”是什麼意思?

  3. 使用 forEach 將事件監聽器添加到所有按鈕

  4. 多次解決承諾是否安全?

  5. 如何在 Node.js 應用程序中使用 AWS 控制 IoT 設備。

  6. 創建自定義 React Hooks:useForm

  7. 將表單數據轉換為 JavaScript 對象

  1. 可訪問的圖像比較——一行 JavaScript

  2. TypeScript 4.1 中的兩個改變遊戲規則的新功能

  3. 對 Node.js 工作線程進行基準測試

  4. 陰影 DOM 樣式

  5. Jira Express:開源瀏覽器擴展,可快速訪問您的 Jira 票證

  6. 為什麼以及如何轉換依賴項

  7. JavaScript 中的 var vs let vs const

  1. React.lazy() - 提升移動性能

  2. 使用 RegEx 驗證電子郵件

  3. 什麼是 CLI?

  4. 紅色,綠色,重構。