Javascript Postgres相当于MySQL';准备好了吗?

Javascript Postgres相当于MySQL';准备好了吗?,javascript,mysql,sql,node.js,postgresql,Javascript,Mysql,Sql,Node.js,Postgresql,我试图从MySQL迁移到Postgres,但遇到了一点问题。我有一个表单,用户在其中填写大约40个字段,然后将这些值插入数据库。对于MySQL,我习惯于这样做: INSERT INTO table_name SET name="John Smith", email="jsmith@gmail.com", website="jsmith.org"; 我还在nodejs中使用mysql模块,这就是我的代码目前的样子: var data = { name: req.body.name, em

我试图从MySQL迁移到Postgres,但遇到了一点问题。我有一个表单,用户在其中填写大约40个字段,然后将这些值插入数据库。对于MySQL,我习惯于这样做:

INSERT INTO table_name SET name="John Smith", email="jsmith@gmail.com", website="jsmith.org";
我还在nodejs中使用
mysql
模块,这就是我的代码目前的样子:

var data = {
  name: req.body.name,
  email: req.body.email,
  website: req.body.website,
  ...
  ...
}

var query = connection.query('INSERT INTO table_name SET ?', data)
由于
SET
不是有效的SQL,如果我想使用Postgres,则使用
pg
模块查询如下:

client.query('INSERT INTO table_name (name, email, website) VALUES ($1, $2, $3)', req.body.name, req.body.email, req.body.website)
考虑到我有将近40个字段,这将变得非常乏味

有没有更好的方法来实现这一点,还是我不得不手工编写查询


谢谢。

因为您已经有了一个包含相关数据的对象

var data = {
  name: req.body.name,
  email: req.body.email,
  website: req.body.website,
  ...
  ...
}
您可以编写一个查询函数来包装客户端的方法,并将对象添加为支持的值:

function insert(client, table, values) {
    const keys = Object.keys(values),
          // IMPORTANT: escape column identifiers. If `values` should come
          // from an uncontrolled source, naive concatenation would allow
          // SQL injection.
          columns = keys.map(k => client.escapeIdentifier(k)).join(', '),
          placeholders = keys.map((k, i) => '$' + (i + 1)).join(', ');

    return client.query(`INSERT INTO ${client.escapeIdentifier(table)} 
                         (${columns}) VALUES (${placeholders})`,
                        // According to docs `query` accepts an array of
                        // values, not values as positional arguments.
                        // If this is not true for your version, use the
                        // spread syntax (...args) to apply values.
                        keys.map(k => values[k]));
}

...

insert(client, 'table_name', data);

或者,您也可以使用重写查询,这看起来相当不错。

这在使用时很容易实现,下面是完整的代码:

var pgp = require('pg-promise')();
var db = pgp(/*connection details*/);

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, null, {table: 'table_name'});
    db.none(insert)
        .then(()=> {
            // success
        })
        .catch(error=> {
            // error
        });
});
API:

方法可以为您生成格式正确的完整
INSERT
语句

它不仅是最简单的方法,而且也是最灵活的方法,因为您无需更改任何内容即可开始生成多插入语句,即,如果
insert
方法的第一个参数是一个对象数组,您将获得多插入查询


如果您只需要请求中的特定属性,那么最好的方法是将它们单独指定为请求之外的属性(可重用,以获得最佳性能):

返回新id-s数组的示例 不进行转换

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.many(insert)
        .then(data=> {
            // success
        })
        .catch(error=> {
            // error
        });
});
app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.map(insert, [], a=>a.id)
        .then(ids=> {
            // ids = array of id-s
        })
        .catch(error=> {
            // error
        });
});
带转换功能

app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.many(insert)
        .then(data=> {
            // success
        })
        .catch(error=> {
            // error
        });
});
app.get('/get', (req, res)=> {
    var insert = pgp.helpers.insert(req.body, cs) + 'RETURNING id';
    db.map(insert, [], a=>a.id)
        .then(ids=> {
            // ids = array of id-s
        })
        .catch(error=> {
            // error
        });
});

很抱歉,这是MySQL特有的语法。您可以编写自己的包装器,但我认为这比一次重写所有查询要花更多的时间。如果
req.body
只有相关的自己的属性,您可以使用
Object.keys
来构建
(column\u name[,…])
列表并生成
值($1,…)
根据键的长度表达。然后再次使用该键列表形成参数列表并应用。但是,另一方面,手动编写查询有利于避免爆炸,如果在某个时候某个随机键突然进入
req.body
。@IljaEverilä,并留下一列白名单以过滤
req.body
。一个临时的解决方案,但是一个支持迁移的合理的桥。@muistooshort实际上,从
req.body
中使用列名的白名单会更好。另外,原始的
数据
对象似乎已经被列入白名单,因此可以使用。感谢您包括
escapeIdentifier
调用。如果你假设ES6+的话,可能比所有那些
+
更干净,但那只是吹毛求疵:)@muistooshort非常正确,值得编辑。我仍然忘记了这一点,即使它是语言中一个如此强大的补充。我该如何做与
ColumnSet
相反的事情呢?我想在查询中忽略一个字段(蜜罐),而不必在查询中写出所有我想要的字段。没关系。。。我将只使用
删除数据。蜜罐
在我使用完之后,它不会被插入。@ipgof目前,
列集
不支持自动求反,只支持包含。但是,它可以接受要跳过的显式列,使用名称前面的
,或者通过设置属性
cnd
-请参见API。只需一个简单的问题,假设我想执行上面演示的插入查询,但也返回一个
id
,如您在文档中所示。我将如何做到这一点?@ipgof我已经添加了一些例子。