【问题标题】:Upsert in Postgres using node.js使用 node.js 在 Postgres 中更新插入
【发布时间】: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

** 结束编辑 **

谁能帮忙?

【问题讨论】:

    标签: postgresql node.js upsert pg


    【解决方案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 的电位器,因此只有整个条目是唯一的。

    【讨论】:

      猜你喜欢
      • 2021-09-06
      • 1970-01-01
      • 2016-03-13
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 2021-02-24
      • 2022-11-10
      相关资源
      最近更新 更多