【问题标题】:pg-promise upsert on postgresql 9.4.11postgresql 9.4.11 上的 pg-promise upsert
【发布时间】:2018-04-12 00:22:46
【问题描述】:

我进行了广泛的搜索,但无法解决这个简单的问题。 我在 nodejs 中编程,并使用 pg-promise 将我的 JSON 文件动态存储到 postgres 9.4.11 数据库中(我不允许升级数据库)。 我的 JSON 每个包含大约一百列,并且我已将其正确解析为三个对象。 1.字段 2. 栏目 3. 表 当我这样做时,Pg-promise 完美地工作:

//-- connection details would be up here  const db = pgp (conn);--
//Insert statement is below


 for (var i=0; i<Object.keys(fields).length; i++){

    const data = [fields[i]];
    const cs = new pgp.helpers.ColumnSet(columns[i]);
    const table = new pgp.helpers.TableName(tables[i],"public");
    const insert = pgp.helpers.insert(data,cs,table);

       db.none(insert)
        .then(data => {
            console.log("Success! Record inserted for " + table);
        })
        .catch(error => {
            //error
            console.log("ALERT!!! Something went wrong with Record in table " + table);
        });
    }

当然,我在 postgresql 9.4.11 上,我不能使用简单的:

const insert = pgp.helpers.insert(data,cs,table) + " ON CONFLICT (id1, uid2, xid3) DO NOTHING";

仅执行插入新项目,因为 UPSERTS 仅从 9.5 开始可用。

我的查询每次运行执行大约 2,000 行插入,我对此感到满意。

我在这方面还很陌生,我希望也许在我的谷歌搜索中我忽略了直接的解决方案。

我见过的最接近的解决方案是存储过程,但我不确定如何实现它。

拜托,stackoverflow,你可能是我唯一的希望!

我只是想确保在 id1、uid2 和 xid3 上匹配的每一行都不会插入到我的 postgres 数据库中。

【问题讨论】:

  • 您的问题与pg-promise 无关。您只需根据您的 PostgreSQL 版本支持的UPSERT 逻辑调整查询即可。为此,请参阅:How to UPSERT in PostgreSQL?
  • @vitaly-t 感谢您的快速回复。所以是的,我看到了那篇文章,我想尝试指示的存储过程方法,创建一个临时表,但使用 pg-promise,我不知道如何。你是在建议,也许我不需要 Pg-promise 来实现我想要做的事情?
  • 您需要更改的内容在pg-promise 之外,您只会使用它来执行查询;)
  • 为什么不使用 CTE (WITH) 查询(而不是存储过程),如下所述:stackoverflow.com/questions/39014190/…
  • 谢谢大家! :-) 花了一整天的时间,我无法让它工作。我会想出别的办法。也许我会查询数据库并存储匹配的 ID 并从 JSON 中加载不匹配的项目。

标签: node.js postgresql postgresql-9.4 upsert pg-promise


【解决方案1】:

所以我学到了一些关于 postgres 的东西。但首先,这是最终对我有用的代码:

 for (var i=0; i<Object.keys(fields).length; i++){

    const data = [fields[i]];
    const cs = new pgp.helpers.ColumnSet(columns[i]);
    const table = new pgp.helpers.TableName(tables[i],"public");
    const insert = pgp.helpers.insert(data,cs,table);
         db.none( 'BEGIN WORK; LOCK TABLE public.'
        + tables[i] + ' IN SHARE ROW EXCLUSIVE MODE; ' 
        + 'INSERT INTO public.'+tables[i]+ ' ('+ columns[i]+')' 
        + 'SELECT 'google.com','another value', 'etc...' WHERE NOT EXISTS(SELECT 1 FROM public.'
        +tables[i] +' WHERE id1 ='+fields[i].id1 
        +' AND uid2 ='+fields[i].uid2 
        +' AND xid3 ='+fields[i].xid3 +');' 
        + 'COMMIT WORK;' ) 
    }

所以我了解到,postgres 不会将双引号内的项目视为值,而是将其视为列。 所以我不得不把我的值数组去掉双引号并用单引号替换,这允许 postgres 接受查询。

使用 pg-promise 将 postgres 查询拼接在一起可能看起来很老套,但这是我发现使用 for 循环加载数百行、数百列宽的数据的最佳方法。

请注意,我有一个值数组,但我将它们写为 'google.com'、'another value'、'etc...' 只是为了让您看到双引号与单引号。

【讨论】:

  • 只要您实际上没有按照您展示的方式进行手动 SQL 连接,您应该没问题。否则,您绝对应该让pg-promise 为您格式化 SQL。最好是将这样的 SQL 放到外部 SQL 文件中,并使用QueryFile
  • 谢谢,vitally-t。我已经搜索了数周,但我没有找到任何示例显示使用查询文件的示例项目,或者可以帮助我使用 pg-promise 来格式化我的 sql,就像我在我的解决方案中构建它一样。如果我能找到一个,它可能会帮助我的执行更加资源友好。目前,我正在考虑尝试将上述查询包装在 db.tx 而不是 db.none 中。再次,反复试验,因为,n00b。作为 nodejs 的新手,我仍在尝试完全掌握 Promise 与回调的概念。
  • QueryFile 的使用示例在API documentationpg-promise-demo 中都有。
  • 谢谢@vitaly-t。我将使用它来改进我的方法。随着事情的进展我会反馈
猜你喜欢
  • 2018-04-11
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-24
相关资源
最近更新 更多