2

我在节点上使用 pg-promise 为 Postgres 建立了一个 API,这很好用,但我正在考虑如何修改 PUT 语句以更好地处理输入中的 NULLS。

以下是 PUT 语句的代码:

    //UPDATE a single record
function updateRecord(req, res, next) {
    db.none('update generic1 SET string1=$1,' +
                               'string2=$2,' +
                               'string3=$3,' +
                               'string4=$4,' +
                               'string5=$5,' +
                               'string6=$6,' +
                               'integer1=$7,' +
                               'integer2=$8,' +
                               'integer3=$9,' +
                               'date1=$10,' +
                               'date2=$11,' +
                               'date3=$12,' +
                               'currency1=$13,' +
                               'currency2=$14' +
            'WHERE id = $15',
            [req.body.string1,
             req.body.string2,
             req.body.string3,
             req.body.string4,
             req.body.string5,
             req.body.string6,
             parseInt(req.body.integer1),
             parseInt(req.body.integer2),
             parseInt(req.body.integer3),
             req.body.date1,
             req.body.date2,
             req.body.date3,
             parseInt(req.body.currency1),
             parseInt(req.body.currency2),
             parseInt(req.params.id)])
        .then(function(){
            res.status(200)
                .json({
                    'status': 'success',
                    'message': 'updated one record'
                });
        })
        .catch(function(err){
            return next(err);
        });
}

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

有没有更好的方法来处理这个?我应该改用 PATCH 动词吗?

4

3 回答 3

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);
        });
}

请参阅助手名称空间;)


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

更新

请注意,库的版本 5.4.0 中更改的方式initskip参数化,请参阅发行说明

从 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,当指定时,它表示方法要返回的值,而不是 throwing Cannot generate an UPDATE without any columns。有关详细信息,请参阅helpers.update

另请参阅:ColumnConfig

于 2016-11-19T20:45:12.727 回答
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]
于 2018-04-06T04:28:56.253 回答
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);
        });
}
于 2016-11-20T19:58:51.960 回答