如何使用 node-postgres 将多行正确插入 PG?

Posted

技术标签:

【中文标题】如何使用 node-postgres 将多行正确插入 PG?【英文标题】:How do I properly insert multiple rows into PG with node-postgres? 【发布时间】:2016-05-01 14:52:36 【问题描述】:

可以像这样插入一行:

client.query("insert into tableName (name, email) values ($1, $2) ", ['john', 'john@gmail.com'], callBack)

这种方法会自动排除任何特殊字符。

如何一次插入多行?

我需要实现这个:

"insert into tableName (name, email) values ('john', 'john@gmail.com'), ('jane', 'jane@gmail.com')"

我可以使用 js 字符串运算符手动编译这些行,但是我需要以某种方式添加特殊字符转义。

【问题讨论】:

您是否有理由不能简单地执行两次 INSERT? 关于 pg 文档,由于性能下降,这种方法是非常不可取的 如果执行 2 次插入而不是 1 次会危及应用程序的性能,那么 node-postgres 根本不适合您。但我相信你以错误的方式看待它,试图优化你不应该的地方。该库可以在 1 秒内轻松插入 10,000 条记录。 您的情况是否令人满意?如果是,请接受。 【参考方案1】:

使用pg-format,如下所示。

var format = require('pg-format');

var values = [
  [7, 'john22', 'john22@gmail.com', '9999999922'], 
  [6, 'testvk', 'testvk@gmail.com', '88888888888']
];
client.query(format('INSERT INTO users (id, name, email, phone) VALUES %L', values),[], (err, result)=>
  console.log(err);
  console.log(result);
);

【讨论】:

【参考方案2】:

另一种使用 PostgreSQL json 函数的方式:

client.query('INSERT INTO table (columns) ' +
  'SELECT m.* FROM json_populate_recordset(null::your_custom_type, $1) AS m',
  [JSON.stringify(your_json_object_array)], function(err, result) 
    if (err) 
      console.log(err);
     else 
      console.log(result);
    
);

【讨论】:

您可能会使用NULL::table 作为类型,但您需要SELECTINSERT 中列出的相同的各个列。 您不必为调用json_populate_recordset() 函数定义自定义类型,而是可以指定要插入的表的名称作为类型。例如,当插入一个名为 foo 的表时,函数调用可能如下所示:json_populate_recordset(null::foo) @Neoheurist 在json结构对应于foo的情况下你是对的。如果json结构不同,则需要定义you_custom_type。【参考方案3】:

您将不得不动态生成查询。虽然有可能,但这是有风险的,如果你做错了,很容易导致 SQL 注入漏洞。查询中的参数索引和传入的参数之间也很容易出现一个错误。

话虽如此,下面是一个示例,说明如何编写此代码,假设您有一组看起来像 name: string, email: string 的用户:

client.query(
  `INSERT INTO table_name (name, email) VALUES $users.map(() => `(?, ?)`).join(',')`,
  users.reduce((params, u) => params.concat([u.name, u.email]), []),
  callBack,
)

另一种方法是使用像@databases/pg(我写的)这样的库:

await db.query(sql`
  INSERT INTO table_name (name, email)
  VALUES $sql.join(users.map(u => sql`($u.name, $u.email)`), ',')
`)

@databases 要求使用sql 标记查询,并使用它来确保您传递的任何用户数据始终自动转义。这也让您可以内联编写参数,我认为这使代码更具可读性。

【讨论】:

【参考方案4】:

按照这篇文章:来自pg-promise 库的Performance Boost 及其建议的方法:

// Concatenates an array of objects or arrays of values, according to the template,
// to use with insert queries. Can be used either as a class type or as a function.
//
// template = formatting template string
// data = array of either objects or arrays of values
function Inserts(template, data) 
    if (!(this instanceof Inserts)) 
        return new Inserts(template, data);
    
    this._rawDBType = true;
    this.formatDBType = function () 
        return data.map(d=>'(' + pgp.as.format(template, d) + ')').join(',');
    ;

一个使用它的例子,就像你的情况一样:

var users = [['John', 23], ['Mike', 30], ['David', 18]];

db.none('INSERT INTO Users(name, age) VALUES $1', Inserts('$1, $2', users))
    .then(data=> 
        // OK, all records have been inserted
    )
    .catch(error=> 
        // Error, no records inserted
    );

它也适用于对象数组:

var users = [name: 'John', age: 23, name: 'Mike', age: 30, name: 'David', age: 18];

db.none('INSERT INTO Users(name, age) VALUES $1', Inserts('$name, $age', users))
    .then(data=> 
        // OK, all records have been inserted
    )
    .catch(error=> 
        // Error, no records inserted
    );

UPDATE-1

有关通过单个 INSERT 查询的高性能方法,请参阅 Multi-row insert with pg-promise。

UPDATE-2

这里的信息现在已经很老了,请参阅Custom Type Formatting 的最新语法。以前的_rawDBType 现在是rawTypeformatDBType 更名为toPostgres

【讨论】:

问题是关于 node-postgress API。您对 pg-promise 的回答是否涵盖了它? @AlexeySh.pg-promise 派生自 node-postgres,所以从某种意义上说,是的。 如果你在这里推荐你自己的图书馆会很好:)【参考方案5】:
client.query("insert into tableName (name, email) values ($1, $2),($3, $4) ", ['john', 'john@gmail.com','john', 'john@gmail.com'], callBack)

没有帮助吗? 此外,您可以手动生成一个字符串进行查询:

insert into tableName (name, email) values (" +var1 + "," + var2 + "),(" +var3 + ", " +var4+ ") "

如果您在这里阅读 https://github.com/brianc/node-postgres/issues/530 ,您可以看到相同的实现。

【讨论】:

这适用于少量插入,但对于数百个插入,您需要循环中的某些内容。此外,您的第二个建议容易受到 SQL 注入的影响。

以上是关于如何使用 node-postgres 将多行正确插入 PG?的主要内容,如果未能解决你的问题,请参考以下文章

将 Async/Await 与 node-postgres 一起使用

在 NodeJS 中,如何使用 node-postgres 模块将 JSON 对象保存为文本?

如何在服务器中使用 node-postgres?

如何在服务器中使用 node-postgres?

求助~~ INSERT INTO....SELECT怎么一次性插入多行数据

使用 node-postgres 在 postgres 中存储文件