ZetCode

Node Postgres 教程

最后修改于 2023 年 10 月 18 日

在本文中,我们将展示如何使用 node-postgres 在 JavaScript 中使用 PostgreSQL 数据库。

node-postgres

node-postgres 是一个用于与 PostgreSQL 数据库交互的 Node.js 模块集合。它支持回调、Promise、async/await、连接池、预处理语句、游标和流式结果。

在我们的示例中,我们还使用 Ramda 库。 见有关更多信息,请参阅 Ramda 教程。

设置 node-postgres

首先,我们安装 node-postgres。

$ npm init -y

我们启动一个新的 Node 应用程序。

$ npm i pg

我们使用 nmp i pg 安装 node-postgres。

$ npm i ramda

此外,我们安装 Ramda 以便更好地处理数据。

cars.sql
DROP TABLE IF EXISTS cars;

CREATE TABLE cars(id SERIAL PRIMARY KEY, name VARCHAR(255), price INT);
INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);

在一些示例中,我们使用 cars 表。

node-postgres 第一个示例

在第一个示例中,我们连接到 PostgreSQL 数据库并返回一个简单的 SELECT 查询结果。

first.js
const pg = require('pg');
const R = require('ramda');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

const client = new pg.Client(cs);
client.connect();

client.query('SELECT 1 + 4').then(res => {

    const result = R.head(R.values(R.head(res.rows)));

    console.log(result);
}).finally(() => client.end());

该示例连接到数据库并发出 SELECT 语句。

const pg = require('pg');
const R = require('ramda');

我们包括 pgramda 模块。

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

这是 PostgreSQL 连接字符串。 它用于建立与数据库的连接。

const client = new pg.Client(cs);
client.connect();

创建客户端。 我们使用 connect 连接到数据库。

client.query('SELECT 1 + 4').then(res => {

    const result = R.head(R.values(R.head(res.rows)));

    console.log(result);
}).finally(() => client.end());

我们发出一个简单的 SELECT 查询。 我们获取结果并将其输出到控制台。 res.rows 是一个对象数组;我们使用 Ramda 获取返回的标量值。 最后,我们使用 end 关闭连接。

$ node first.js
5

node-postgres 列名

在下面的示例中,我们获取数据库的列名。

column_names.js
const pg = require('pg');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

const client = new pg.Client(cs);

client.connect();

client.query('SELECT * FROM cars').then(res => {

    const fields = res.fields.map(field => field.name);

    console.log(fields);

}).catch(err => {
    console.log(err.stack);
}).finally(() => {
    client.end()
});

列名使用 res.fields 属性检索。 我们还使用 catch 子句来输出潜在的错误。

$ node column_names.js
[ 'id', 'name', 'price' ]

输出显示了 cars 表的三个列名。

选择所有行

在下一个示例中,我们从数据库表中选择所有行。

all_rows.js
const pg = require('pg');
const R = require('ramda');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

const client = new pg.Client(cs);

client.connect();

client.query('SELECT * FROM cars').then(res => {

    const data = res.rows;

    console.log('all data');
    data.forEach(row => {
        console.log(`Id: ${row.id} Name: ${row.name} Price: ${row.price}`);
    })

    console.log('Sorted prices:');
    const prices = R.pluck('price', R.sortBy(R.prop('price'), data));
    console.log(prices);

}).finally(() => {
    client.end()
});

该示例输出 cars 表中的所有行和已排序的汽车价格列表。

$ node all_rows.js
all data
Id: 1 Name: Audi Price: 52642
Id: 2 Name: Mercedes Price: 57127
Id: 3 Name: Skoda Price: 9000
Id: 4 Name: Volvo Price: 29000
Id: 5 Name: Bentley Price: 350000
Id: 6 Name: Citroen Price: 21000
Id: 7 Name: Hummer Price: 41400
Id: 8 Name: Volkswagen Price: 21600
Sorted prices:
[ 9000, 21000, 21600, 29000, 41400, 52642, 57127, 350000 ]

node-postgres 参数化查询

参数化查询使用占位符而不是直接将值写入语句中。 参数化查询提高了安全性和性能。

parameterized.js
const pg = require('pg');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

const client = new pg.Client(cs);

client.connect();

const sql = 'SELECT * FROM cars WHERE price > $1';
const values = [50000];

client.query(sql, values).then(res => {

    const data = res.rows;

    data.forEach(row => console.log(row));

}).finally(() => {
    client.end()
});

该示例在简单的 SELECT 语句中使用参数化查询。

const sql = 'SELECT * FROM cars WHERE price > $1';

这是 SELECT 查询。 $1 是一个占位符,稍后将以安全的方式替换为值。

const values = [50000];

这些是要插入到参数化查询中的值。

client.query(sql, values).then(res => {

这些值作为第二个参数传递给 query 方法。

$ node parameterized.js
{ id: 1, name: 'Audi', price: 52642 }
{ id: 2, name: 'Mercedes', price: 57127 }
{ id: 5, name: 'Bentley', price: 350000 }

node-postgres 与 async/await

Node Postgres 支持 async/await 语法。

async_await.js
const pg = require('pg');
const R = require('ramda');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

async function fetchNow() {

    const client = new pg.Client(cs);

    try {
        await client.connect();

        let result = await client.query('SELECT now()');
        return R.prop('now', R.head(result.rows));
    } finally {
        client.end()
    }
}

fetchNow().then(now => console.log(now));

该示例使用 async/await 输出 SELECT now 查询的结果。

$ node async_await.js
2019-02-17T11:53:01.447Z

node-postgres rowmode

默认情况下,node-postgres 将数据作为对象数组返回。 我们可以告诉 node-postgres 将数据作为数组的数组返回。

row_mode.js
const pg = require('pg');
const R = require('ramda');

const cs = 'postgres://postgres:s$cret@localhost:5432/ydb';

const client = new pg.Client(cs);

client.connect();

const query = {
    text: 'SELECT * FROM cars',
    rowMode: 'array'
};

client.query(query).then(res => {

    const data = res.rows;

    console.log('all data');
    data.forEach(row => {
        console.log(`Id: ${row[0]} Name: ${row[1]} Price: ${row[2]}`);
    })

    console.log('Sorted prices:');

    const prices = data.map(x => x[2]);

    const sorted = R.sort(R.comparator(R.lt), prices);
    console.log(sorted);

}).finally(() => {
    client.end()
});

该示例显示 cars 表中的所有行。 它启用数组行模式。

const query = {
    text: 'SELECT * FROM cars',
    rowMode: 'array'
};

我们使用配置对象,在其中将 rowMode 设置为 array

console.log('all data');
data.forEach(row => {
    console.log(`Id: ${row[0]} Name: ${row[1]} Price: ${row[2]}`);
})

现在我们遍历一个数组的数组。

$ node row_mode.js
all data
Id: 1 Name: Audi Price: 52642
Id: 2 Name: Mercedes Price: 57127
Id: 3 Name: Skoda Price: 9000
Id: 4 Name: Volvo Price: 29000
Id: 5 Name: Bentley Price: 350000
Id: 6 Name: Citroen Price: 21000
Id: 7 Name: Hummer Price: 41400
Id: 8 Name: Volkswagen Price: 21600
Sorted prices:
[ 9000, 21000, 21600, 29000, 41400, 52642, 57127, 350000 ]

node-postgres 连接池示例

连接池提高了数据库应用程序的性能。 它在 Web 应用程序中特别有用。

pooled.js
const pg = require('pg');

var config = {
    user: 'postgres',
    password: 's$cret',
    database: 'ydb'
}

const pool = new pg.Pool(config);

pool.connect()
    .then(client => {
        return client.query('SELECT * FROM cars WHERE id = $1', [1])
            .then(res => {
                client.release();
                console.log(res.rows[0]);
            })
            .catch(e => {
                client.release();
                console.log(e.stack);
            })
  }).finally(() => pool.end());

该示例展示了如何设置使用连接池的示例。 完成查询后,我们调用 client.release 方法将连接返回到池中。

}).finally(() => pool.end());

pool.end 耗尽池中的所有活动客户端,断开它们,并关闭池中的任何内部计时器。 这用于此类示例之类的脚本中。 在 Web 应用程序中,我们可以在 Web 服务器关闭时调用它,或者完全不调用它。

来源

node-postgres Github 页面

在本文中,我们使用了 node-postgres 在 Node.js 中与 PostgreSQL 交互。

作者

我叫 Jan Bodnar,是一位充满激情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

查看 所有 JavaScript 教程。