使用 node.js 在 Postgres 中更新插入
Posted
技术标签:
【中文标题】使用 node.js 在 Postgres 中更新插入【英文标题】:Upsert in Postgres using node.js 【发布时间】:2011-12-16 03:31:35 【问题描述】:我正在尝试使用带有 pg 扩展名的 node.js(版本 0.5.4)在 postgres 数据库中进行插入或更新。
到目前为止,我有以下代码: (...)
client.query(
text: "update users set is_active = 0, ip = $1 where id=$2",
values: [ip,id]
, function(u_err, u_result)
debug(socket_id,"update query result: ",u_result);
debug(socket_id,"update query error: ",u_err);
date_now = new Date();
var month = date_now.getMonth() + 1;
if(!u_err)
client.query(
text: 'insert into users (id,first_name,last_name,is_active,ip,date_joined) values' +
'($1,$2,$3,$4,$5,$6)',
values: [
result.id,
result.first_name,
result.last_name,
1,
ip,
date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
]
, function(i_err, i_result)
debug(socket_id,"insert query result: ",i_result);
debug(socket_id,"insert query error: ",i_err);
);
);
问题在于,虽然两个查询都有效,但问题始终是两者都运行,而不是仅在更新失败时运行插入函数。
代码中的调试函数输出如下:
更新
Object type="update query result: ", debug_value=...
home (linha 56)
Object type="update query error: ", debug_value=null
home (linha 56)
Object type="insert query result: "
home (linha 56)
Object type="insert query error: ", debug_value=...
插入
Object type="update query result: ", debug_value=...
home (linha 56)
Object type="update query error: ", debug_value=null
home (linha 56)
Object type="insert query result: ", debug_value=...
home (linha 56)
Object type="insert query error: ", debug_value=null
** 编辑 **
来自 node-postgres 开发者的回答:
可以检索受插入影响的行数和 更新。它没有在本机绑定中完全实现,但确实 在纯 javascript 版本中工作。我将在 下一周或两周。同时使用纯javascript版本和 看看这里:
https://github.com/brianc/node-postgres/blob/master/test/integration/client/result-metadata-tests.js
** 结束编辑 **
谁能帮忙?
【问题讨论】:
【参考方案1】:您的问题的直接答案是使用存储过程来执行 upsert。
http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE
这样的东西与 pg 模块配合得很好。
client.query(
text: "SELECT upsert($1, $2, $3, $4, $5, $6)"
values: [ obj.id,
obj.first_name,
obj.last_name,
1,
ip,
date_now.getFullYear() + "-" + month + "-" + date_now.getDate() + " " + date_now.getHours() + ":" + date_now.getMinutes() + ":" + date_now.getSeconds()
]
, function(u_err, u_result)
if(err) // this is a real error, handle it
// otherwise your data is updated or inserted properly
);
当然,这假设您正在使用某种模型对象,该对象具有您需要的所有值,即使它们没有改变。您必须将它们全部传递到 upsert 中。如果您坚持按照此处显示的方式执行此操作,则可能应该在更新后检查实际的错误对象,以确定它是否因为该行已经存在或其他原因而失败(这是真正的 db 错误需要处理)。
那么您必须处理更新失败与插入完成之间的潜在竞争条件。如果其他一些函数尝试使用相同的 id 插入,那么你就有问题了。交易对此有好处。这就是我现在所得到的。希望对您有所帮助。
【讨论】:
嗨,马可!感谢您的回答!我与 node.js 的 pg 模块的开发人员取得了联系,我编辑了这个问题以突出他的回答!关于您的回答,这是我最初的意图,但是当我使用 heroku 进行开发并且需要点击来迁移数据库时,我遇到了一个问题,因为我认为点击无法导出存储过程。 (虽然我可能是错的)无论如何你能告诉我存储过程的性能问题吗?关于并发问题,我认为它们不适用,但是如果您可以发布一些指向 ilustrate Transicions 的链接,那将是完美的... ;) 再次感谢!【参考方案2】:我在使用 JDBC 连接到 PG 实例时遇到了这个问题。我最终使用的解决方案是:
UPDATE table SET field='C', field2='Z' WHERE id=3;
INSERT INTO table (id, field, field2)
SELECT 3, 'C', 'Z'
WHERE NOT EXISTS (SELECT 1 FROM table WHERE id=3);
如果记录不存在,则更新不执行任何操作,如果记录存在,则插入不执行任何操作。它工作得很好,是一个基于 SQL 的解决方案与一个存储过程。
这是最初的问题: Insert, on duplicate update in PostgreSQL?
【讨论】:
我实际上也按照这些思路实现了一些东西。但是我测试了第一个查询的响应,如果没有行受到影响,则只运行第二个查询。这是/仅在我正在使用的github.com/brianc/node-postgres 的本机 js 模式中支持。感谢您抽出宝贵时间回答!【参考方案3】:我有一个电子元件数据库,我可以在其中添加从电子垃圾中回收或购买的新元件,我这样做的方式是:
const upsertData = (request, response) =>
const
category, type, value, unit, qty,
= request.body;
pool.query(`DO $$
BEGIN
IF EXISTS
( SELECT 1
FROM elab
WHERE category='$category'
AND type='$type'
AND value='$value'
AND unit='$unit'
)
THEN
UPDATE elab
SET qty = qty + $qty
WHERE category='$category'
AND type='$type'
AND value='$value'
AND unit='$unit';
ELSE
INSERT INTO elab
(category, type, value, unit, qty)
values ('$category', '$type', '$value', '$unit', $qty);
END IF ;
END
$$ ;`, (error, results) =>
if (error)
throw error;
response.status(201).send('Task completed lol');
);
;
这样做的原因是任何条目的唯一唯一列是 ID,它会自动更新,其他列都不是唯一的,只有整个条目是例如您可以将 100 kOhm 电阻器用作电位器或“正常”电阻器 - 您可以使用值不同于 100 kOhm 的电位器,因此只有整个条目是唯一的。
【讨论】:
以上是关于使用 node.js 在 Postgres 中更新插入的主要内容,如果未能解决你的问题,请参考以下文章
使用 postgres 和 node js 在单个语句中执行多个查询
Node.js Sequelize UUID 主键 + Postgres