使用node.js在Postgres中进行Upsert

时间:2011-10-26 23:34:17

标签: postgresql node.js upsert pg

我正在尝试使用带扩展名为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);
                });
            }
        });

问题是,虽然两个查询都有效,但问题始终是同时运行,而不是仅在更新失败时才运行insert函数。

代码输出中的调试函数类似于:

更新

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}

**编辑**

ANSWER FROM node-postgres开发者:

  

可以检索受插入影响的行数   更新。它没有在本机绑定中完全实现,但确实如此   在纯JavaScript版本中工作。我会在这个内部研究这个   下周或者两周。同时使用纯javascript版本和   看看这里:

     

https://github.com/brianc/node-postgres/blob/master/test/integration/client/result-metadata-tests.js

**结束编辑**

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:2)

您的问题的直接答案是使用存储过程进行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插入,则表示您遇到了问题。交易对此有利。这就是我现在所做的一切。希望它有所帮助。

答案 1 :(得分: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?

答案 2 :(得分:0)

我有一个电子零件数据库,可以在其中添加我可以从电子垃圾中回收的零件或作为新零件购买的零件,我的操作方式是:

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,该ID会自动更新,其他列都不是唯一的,例如整个条目都是唯一的。您可以使用一个100 kOhm的电阻器作为电位器,也可以使用一个“普通”电阻器-您可以使用一个不同于100 kOhm的电阻器,因此只有整个输入是唯一的。