如何在 POST body 的基础上创建动态插入语句
How to create dynamic insert statement on the basis of POST body
正文对象中的属性数量不同,这是基于一个值user_type
。
如果 user_type
是 job_seeker 那么 body 对象具有这些属性 --> username, user_type, name, email , 密码, 简历, resume_date_time, salary_expectation。我创建了这样的硬编码插入语句 -->
insert into users (username, user_type, name, email, password, resume, resume_date_time, salary_expectation) values (?, ?, ?, ?, ?, ?, ?, ?);
如果 user_type
是 employer 那么正文对象具有这些属性 --> 用户名,user_type,姓名,电子邮件,密码,company_name、company_profile。本例的插入语句是这样的 -->
insert into users (username, user_type, name, email, password, company_name, company_profile) values (?, ?, ?, ?, ?, ?, ?);
那么,如何根据不同的编号创建动态插入查询。 POST 请求正文中的属性?
这不是一个好的答案,但它确实有效,所以我会解决这个小问题,但如果有人知道这个,请 post 回答。
let keys = [];
let values = [];
let escapedsql = [];
Object.keys(req.body).forEach(key => {
keys.push(key);
values.push(req.body[key]);
escapedsql.push('?')
})
let postBody = 'insert into users (' + keys.join() + ') values (' + escapedsql.join() + ')';
let sql = connection.format(postBody, values);
这是由 mysqljs
模块为您处理的,因此您无需对其进行过度思考或过度设计。将您的插入负载作为一个对象提供,其中键与您的 table 字段名称共享相同的命名。无论您提供什么,都将在插入中使用。如果您不提供字段,它将遵循数据库模式中的 table 默认值(如果您这样设置,id
将自动填充和递增,created_at
, timestamp
或其他类似的日期字段,如果字段设置为在未提供值时使用默认值,则将使用该默认值。
有关详细信息,请参阅此处的文档:https://github.com/mysqljs/mysql#escaping-query-values
下面是使用您提供的两个场景的示例。
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'me',
password: 'secret',
database: 'my_db'
});
connection.connect();
let job_seeker = {
username: 'j.smith',
user_type: 'job_seeker',
name: 'john smith',
email: 'j.smith@example.com',
password: 'keyboard_cat',
resume: true,
resume_date_time: '2109-01-01',
salary_expectation: 100000
};
let employer = {
username: 'b.burke',
user_type: 'employer',
name: 'betty burke',
email: 'b.burke@example.com',
password: 'admin_cat',
company_name: 'Acme Inc.',
company_profile: 'http://acme.example.com/about_us/'
};
connection.query('INSERT INTO users SET ?', job_seeker, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
connection.query('INSERT INTO users SET ?', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// if a scenario exists where you might encounter unique key conflicts, consider using a query model that will update on duplicates:
connection.query('INSERT INTO users SET ? ON DUPLICATE KEY UPDATE', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// this would update every field provided in the employer object. If you didn't want to update every fields, you'd have to list out only the fields you'd like to update:
connection.query('INSERT INTO users SET ? ON DUPLICATE KEY UPDATE name = VALUES(name)', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// in the above example, only the name field will be updated if a duplicate is found, even though the full employer object is provided.
如果在将 POST
主体传递到代码中的这一步之前正确构建主体,您可以节省一些时间,让它流向查询函数,而无需额外的工作或对象构造或操纵。
根据评论编辑
如果您的计划是包含一些查询参数,您可能希望使用 UPDATE 而不是 INSERT。无论哪种方式,我们都可以以此为例来说明如何说明 mysqljs
模块提供的动态功能。
每次使用 ?
时,它都是一个占位符,映射到函数中后面的数组索引。
在我链接的文档部分,您可以看到一个示例,其中 4 ?
映射到后面数组中提供的 4 个值。您只需要确保数组中值的顺序与其问号对应的正确顺序一致即可。
如果我们想通过一个对象在一个查询中解决所有问题,我们可以为 POST
对象添加一些复杂性,使其包含我们查询所需的所有信息。使用您的示例,考虑以下内容:
// you could define the following object as we have for this example, or it could be coming right from req.body
let update_payload = {
table_name = 'users',
query_field = 'email',
query_value = 'j.smith.old@example.com',
job_seeker = {
username: 'j.smith',
user_type: 'job_seeker',
name: 'john smith',
email: 'j.smith.new@example.com',
password: 'keyboard_cat_new',
resume: true,
resume_date_time: '2109-01-01',
salary_expectation: 100000
}
};
connection.query('UPDATE ?? SET ? WHERE ?? = ? ', [update_payload.table_name, update_payload.job_seeker, update_payload.query_field, update_payload.query_value], function(error, results, fields) {
if (error) throw error;
console.log(results);
});
// expected console output…
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 1 Warnings: 0',
protocol41: true,
changedRows: 1
}
注意: 你会看到我有时使用 ??
而其他时候使用 ?
。这是模块的一个特性,它提供转义以防止 SQL 注入。根据您的数据库配置、体系结构、字段类型和您的个人安全策略的具体情况,在何时何地使用 single 与 double 的必要性会有所不同,并且需要使用您自己的代码库进行测试。
正文对象中的属性数量不同,这是基于一个值user_type
。
如果 user_type
是 job_seeker 那么 body 对象具有这些属性 --> username, user_type, name, email , 密码, 简历, resume_date_time, salary_expectation。我创建了这样的硬编码插入语句 -->
insert into users (username, user_type, name, email, password, resume, resume_date_time, salary_expectation) values (?, ?, ?, ?, ?, ?, ?, ?);
如果 user_type
是 employer 那么正文对象具有这些属性 --> 用户名,user_type,姓名,电子邮件,密码,company_name、company_profile。本例的插入语句是这样的 -->
insert into users (username, user_type, name, email, password, company_name, company_profile) values (?, ?, ?, ?, ?, ?, ?);
那么,如何根据不同的编号创建动态插入查询。 POST 请求正文中的属性?
这不是一个好的答案,但它确实有效,所以我会解决这个小问题,但如果有人知道这个,请 post 回答。
let keys = [];
let values = [];
let escapedsql = [];
Object.keys(req.body).forEach(key => {
keys.push(key);
values.push(req.body[key]);
escapedsql.push('?')
})
let postBody = 'insert into users (' + keys.join() + ') values (' + escapedsql.join() + ')';
let sql = connection.format(postBody, values);
这是由 mysqljs
模块为您处理的,因此您无需对其进行过度思考或过度设计。将您的插入负载作为一个对象提供,其中键与您的 table 字段名称共享相同的命名。无论您提供什么,都将在插入中使用。如果您不提供字段,它将遵循数据库模式中的 table 默认值(如果您这样设置,id
将自动填充和递增,created_at
, timestamp
或其他类似的日期字段,如果字段设置为在未提供值时使用默认值,则将使用该默认值。
有关详细信息,请参阅此处的文档:https://github.com/mysqljs/mysql#escaping-query-values
下面是使用您提供的两个场景的示例。
var mysql = require('mysql');
var connection = mysql.createConnection({
host: 'localhost',
user: 'me',
password: 'secret',
database: 'my_db'
});
connection.connect();
let job_seeker = {
username: 'j.smith',
user_type: 'job_seeker',
name: 'john smith',
email: 'j.smith@example.com',
password: 'keyboard_cat',
resume: true,
resume_date_time: '2109-01-01',
salary_expectation: 100000
};
let employer = {
username: 'b.burke',
user_type: 'employer',
name: 'betty burke',
email: 'b.burke@example.com',
password: 'admin_cat',
company_name: 'Acme Inc.',
company_profile: 'http://acme.example.com/about_us/'
};
connection.query('INSERT INTO users SET ?', job_seeker, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
connection.query('INSERT INTO users SET ?', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// if a scenario exists where you might encounter unique key conflicts, consider using a query model that will update on duplicates:
connection.query('INSERT INTO users SET ? ON DUPLICATE KEY UPDATE', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// this would update every field provided in the employer object. If you didn't want to update every fields, you'd have to list out only the fields you'd like to update:
connection.query('INSERT INTO users SET ? ON DUPLICATE KEY UPDATE name = VALUES(name)', employer, function(error, results, fields) {
if (error) throw error;
console.log(results.insertId);
});
// in the above example, only the name field will be updated if a duplicate is found, even though the full employer object is provided.
如果在将 POST
主体传递到代码中的这一步之前正确构建主体,您可以节省一些时间,让它流向查询函数,而无需额外的工作或对象构造或操纵。
根据评论编辑
如果您的计划是包含一些查询参数,您可能希望使用 UPDATE 而不是 INSERT。无论哪种方式,我们都可以以此为例来说明如何说明 mysqljs
模块提供的动态功能。
每次使用 ?
时,它都是一个占位符,映射到函数中后面的数组索引。
在我链接的文档部分,您可以看到一个示例,其中 4 ?
映射到后面数组中提供的 4 个值。您只需要确保数组中值的顺序与其问号对应的正确顺序一致即可。
如果我们想通过一个对象在一个查询中解决所有问题,我们可以为 POST
对象添加一些复杂性,使其包含我们查询所需的所有信息。使用您的示例,考虑以下内容:
// you could define the following object as we have for this example, or it could be coming right from req.body
let update_payload = {
table_name = 'users',
query_field = 'email',
query_value = 'j.smith.old@example.com',
job_seeker = {
username: 'j.smith',
user_type: 'job_seeker',
name: 'john smith',
email: 'j.smith.new@example.com',
password: 'keyboard_cat_new',
resume: true,
resume_date_time: '2109-01-01',
salary_expectation: 100000
}
};
connection.query('UPDATE ?? SET ? WHERE ?? = ? ', [update_payload.table_name, update_payload.job_seeker, update_payload.query_field, update_payload.query_value], function(error, results, fields) {
if (error) throw error;
console.log(results);
});
// expected console output…
OkPacket {
fieldCount: 0,
affectedRows: 1,
insertId: 0,
serverStatus: 2,
warningCount: 0,
message: '(Rows matched: 1 Changed: 1 Warnings: 0',
protocol41: true,
changedRows: 1
}
注意: 你会看到我有时使用 ??
而其他时候使用 ?
。这是模块的一个特性,它提供转义以防止 SQL 注入。根据您的数据库配置、体系结构、字段类型和您的个人安全策略的具体情况,在何时何地使用 single 与 double 的必要性会有所不同,并且需要使用您自己的代码库进行测试。