Javascript Postgres相当于MySQL';准备好了吗?
我试图从MySQL迁移到Postgres,但遇到了一点问题。我有一个表单,用户在其中填写大约40个字段,然后将这些值插入数据库。对于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
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我已经添加了一些例子。