如何使用nodejs pg-promise库将带有uuid数组的记录插入pg表

Posted

技术标签:

【中文标题】如何使用nodejs pg-promise库将带有uuid数组的记录插入pg表【英文标题】:how to insert a record with a uuid array into a pg table using nodejs pg-promise library 【发布时间】:2015-11-23 01:29:07 【问题描述】:

我需要在我的数据库中有一个表,其中包含一个单列,该列是一个 uuid 对象数组(uuid[] 类型)

但是当我尝试使用名为 pg-promise 的 nodejs 库插入它时,它失败了

我收到以下错误消息,告诉我需要重写演员表或表达式

"name":"error","length":206,"severity":"ERROR","code":"42804","hint":"You will need to rewrite or cast the expression.","position":"230","file":"src\\backend\\parse
r\\parse_target.c","line":"510","routine":"transformAssignedExpr"

这很奇怪 因为当我尝试将单个 uuid 输入到同一个确切表上的另一列时我绝对没有问题(意思是,我表示 uuid 没有问题,顺便说一句,我将它们创建为来自另一个库的文本变量,但它们很旧文本变量)

当我尝试将一个 TEXT 对象数组输入到同一列时也没有问题(如果我将表更改为具有 TEXT[] 列而不是 UUID[] 列)

这是我的代码

////////////////

var Promise = require('bluebird');
var pgpLib = require('pg-promise');
var pgp = pgpLib();
var cn = confUtil.pgDbConnectionConfiguration();
var db = pgp(cn);

//////////////////

var newEntity=;
newEntity.hash      = uuid.v4();    
newEntity.location  = X:2394876,Y:2342342;
newEntity.mother    = uuid.v4();
newEntity.timestamp = Date.now();
newEntity.content   = content:"blah";
newEntity.sobList   = [uuid.v4(),uuid.v4(),uuid.v4()];
addEntity (newEntity);

////////////////////

function addEntity(newEntity) 
    var insertEntityQueryPrefix='insert into entities (';
    var insertEntityQueryMiddle=') values (';
    var insertEntityQueryPostfix="";
    var insertEntityQuery="";

    Object.keys(newEntity).forEach(function(key)
        insertEntityQueryPrefix=insertEntityQueryPrefix+'"'+key+'",';
        insertEntityQueryPostfix=insertEntityQueryPostfix+'$'+key+',';
    );
    insertEntityQueryPrefix=insertEntityQueryPrefix.slice(0,-1);
    insertEntityQueryPostfix=insertEntityQueryPostfix.slice(0,-1)+")";  
    insertEntityQuery=insertEntityQueryPrefix+insertEntityQueryMiddle+insertEntityQueryPostfix;

    //longStoryShort  this is how the query template i used looked like
    /*
        "insert into entities ("hash","location","mother","timestamp","content","sobList") values ($hash,$location,$mother,$timestamp,$content,$sobList)"
    */
    //and this is the parameters object i fed to the query i ran it when it failed
    /*
        
            "hash": "912f6d85-8b47-4d44-98a2-0bbef3727bbd",
            "location": 
                "X": 2394876,
                "Y": 2342342
            ,
            "mother": "87312241-3781-4d7c-bf0b-2159fb6f7f74",
            "timestamp": 1440760511354,
            "content": 
                "content": "bla"
            ,
            "sobList": [
                "6f2417e1-b2a0-4e21-8f1d-31e64dea6358",
                "417ade4b-d438-4565-abd3-a546713be194",
                "e4681d92-0c67-4bdf-973f-2c6a900a5fe4"
            ]
        
    */

    return db.tx(function () 
        var processedInsertEntityQuery = this.any(insertEntityQuery,newEntity);
        return Promise.all([processedInsertEntityQuery])
    )
    .then(
        function (data) 
            return newEntity;
        , 
        function (reason) 
            throw new Error(reason);
        );

【问题讨论】:

【参考方案1】:

插入 UUID-s 数组是一种特殊情况,需要显式类型转换,因为您将 UUID-s 作为文本字符串数组传递到类型 uuid[]

您需要更改您的INSERT 查询:将$sobList 替换为$sobList::uuid[]。这将指示 PostgeSQL 将字符串数组转换为 UUID 数组。

与您的问题无关,仅执行单个请求时,您不需要在 db.tx 内使用 Promise.all。您可以简单地从插入请求中返回结果:

return this.none(insertEntityQuery,newEntity);

虽然使用事务来执行单个请求同样毫无意义:)

更新

最新版本的pg-promise 支持Custom Type Formatting,因此您可以为查询格式化编写自己的自定义类型,避免显式类型转换。

对于在数组中使用 UUID-s 的示例,您可以实现自己的 UUID 类型:

const UUID = a => (rawType = true, toPostgres = () => a.v4());

对于数组或单独的任何uuidValue,您可以使用UUID(uuidValue) 进行自动格式化。

【讨论】:

非常感谢。这正是问题所在。我感觉这就是原因,但不知道如何在语法上添加强制转换。 现在我想起来了。你和写 pg-promise 的人一样,不是吗?好吧,干得好! :) 很棒的库(尽管正如你所注意到的,我刚开始使用它,而且大多是错误的方式)但是直接来自库的整个承诺支持很棒。 是的,就是我 :) 随时在项目网站上提问:pg-promise 添加了使用Custom Type Formatting 的示例,作为替代;)

以上是关于如何使用nodejs pg-promise库将带有uuid数组的记录插入pg表的主要内容,如果未能解决你的问题,请参考以下文章

使用 pg-promise 的连接池

我应该在哪里初始化 pg-promise

如何使用带有c ++的opencv库将下图中的黑色像素更改为红色像素

如何通过 Node JS 使用自己的库将联系人添加到 Mailchimp 中的列表/受众

pg-promise:在事务中的下一个查询中使用一个查询的结果

使用nodejs客户端库将图像作为base64编码发送到google云视觉API