使用pg-promise跳过更新列

时间:2016-11-19 20:01:55

标签: node.js pg-promise

我已经在节点上使用pg-promise为Postgres获得了API,这很有效但我正在思考如何修改PUT语句以更好地处理输入中的NULLS。

以下是PUT语句的代码:

[Key]
public Guid AccountGuid { get; set; }

现在这个语句有效,但如果我将NULLS传递给下一次更新,它也会删除现有值。例如,如果我只想更新string1和date2,我必须发送整个json对象,或者所有其他值都设置为NULL。

有没有更好的方法来解决这个问题?我应该使用PATCH动词吗?

3 个答案:

答案 0 :(得分:2)

我是pg-promise;)的作者

var pgp = require('pg-promise')({
    capSQL: true // capitalize all generated SQL
});

// generic way to skip NULL/undefined values for strings:
function str(col) {
    return {
        name: col,
        skip: function () {
            var val = this[col];
            return val === null || val === undefined;
        }
    };
}

// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(col) {
    return {
        name: col,
        skip: function () {
            var val = this[col];
            return val === null || val === undefined;
        },
        init: function () {
            return parseInt(this[col]);
        }
    };
}

// Creating a reusable ColumnSet for all updates:
var csGeneric = new pgp.helpers.ColumnSet([
    str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
    str('string6'), int('integer1'), int('integer2'), int('integer3'),
    str('date1'), str('date2'), str('date3')
], {table: 'generic1'});

// Your new request handler:
function updateRecord(req, res, next) {

    var update = pgp.helpers.update(req.body, csGeneric) + ' WHERE id = ' +
        parseInt(req.params.id);

    db.none(update)
        .then(function () {
            res.status(200)
                .json({
                    'status': 'success',
                    'message': 'updated one record'
                });
        })
        .catch(function (err) {
            return next(err);
        });
}

请参阅helpers命名空间;)

或者,您可以对每列进行自己的验证,然后相应地生成UPDATE查询,但它不会优雅;)

<强>更新

请注意,initskip参数化的方式在图书馆的5.4.0版中已更改,请参阅the release notes

从版本5.4.0开始,您可以简化代码:

// generic way to skip NULL/undefined values for strings:
function str(column) {
    return {
        name: column,
        skip: c => c.value === null || c.value === undefined
    };
}

// generic way to skip NULL/undefined values for integers,
// while parsing the type correctly:
function int(column) {
    return {
        name: column,
        skip: c => c.value === null || c.value === undefined,
        init: c => +c.value
    };
}

如果你想跳过根本没有传入的属性,因此甚至不存在于对象中,那么代替这个:

skip: c => c.value === null || c.value === undefined

你可以这样做:

skip: c => !c.exists

<强>更新

库的5.6.7版本对此进行了进一步的改进 - 选项emptyUpdate,当指定时表示方法返回的值,而不是抛出Cannot generate an UPDATE without any columns。有关详细信息,请参阅helpers.update

另请参阅:ColumnConfig

答案 1 :(得分:1)

替代解决方案:

function updateFoo(req, res){ 
    let {name, email, password} = req.body; 
    // Ex: req.body = { name: 'foo', password: 'bar' }
    let data = { name, email, password }; // {name: 'foo', email:undefined, password:'bar}
    //Remove ONLY undefined keys from data
    Object.keys(data).forEach( key => { if(data[key] === undefined) delete data[key] });

    let query = 'UPDATE foo SET';

    let i = 1;
    Object.keys(data).forEach( key => { query += ` ${key}=$${index},`; i++; })
    query = query.slice(0, -1) // Remove exceeding comma
    query += ` WHERE id=$${i}`;

    let values = Object.values(data); // ['foo', 'bar']
    values.push(req.params.id);

    // .....
    // query = 'UPDATE foo SET  name=$1, password=$2 WHERE id=$3'
    // values = ['foo', 'bar', req.params.id]

答案 2 :(得分:0)

谢谢@ vitaly-t!更快更清洁,总是很好的结果:)

作为参考,我还包括使用如上所述的帮助者的插入语句。

    //firstly create a function that skips the nulls for strings
function str(column) {
    return {
        name: column,
        skip: c => c.value === null || c.value === undefined || !c.exists
    };
}

//now a function that skips nulls for integers, while parsing type
function int(column) {
    return {
        name: column,
        skip: c => c.value === null || c.value === undefined || !c.exists,
        init: c => +c.value
    };
}

//creating a column set for all updates
var usefulColumSet = new pgp.helpers.ColumnSet([
    str('string1'), str('string2'), str('string3'), str('string4'), str('string5'),
    str('string6'), int('integer1'), int('integer2'), int('integer3'),
    str('date1'), str('date2'), str('date3'), int('currency1'), int('currency2')
], {table: 'generic1'});

//*********************CREATE a single record*************************
function createRecord(req, res, next) {
    var insert = pgp.helpers.insert(req.body, usefulColumSet);

    db.none(insert)
        .then(function(){
            res.status(200)
                .json({
                    status: 'success',
                    message: 'Inserted one record successully'
                });
        })
        .catch(function(err){
            return next(err);
        });
}


//************************UPDATE a single record*************
function updateRecord(req, res, next) {
    var update = pgp.helpers.update(req.body, usefulColumSet) + ' WHERE id = ' + parseInt(req.params.id);

    db.none(update)
        .then(function() {
            res.status(200)
                .json({
                    status: 200,
                    message: 'updated a single record cleanly'
                });
        })
        .catch(function(err) {
            return next(err);
        });
}