使用 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 和 postgres 听

Node.js Sequelize UUID 主键 + Postgres

如何将 postgres 查询分配给 node.js、Discord bot 和 postgres 集成中的变量?

node.js + postgres 数据库事务管理

AWS:启动启动服务器(Node.js + Postgres)