【问题标题】:How to create dynamic insert statement on the basis of POST body如何在 POST 正文的基础上创建动态插入语句
【发布时间】:2019-11-24 11:22:05
【问题描述】:

body 对象中的属性数量基于值user_type 不同。

如果user_typejob_seeker,那么body 对象具有这些属性--> username、user_type、name、email、password、resume、resume_date_time、salary_expectation。我已经创建了这样的硬编码插入语句-->

insert into users (username, user_type, name, email, password, resume, resume_date_time, salary_expectation) values (?, ?, ?, ?, ?, ?, ?, ?);

如果user_typeemployer,那么body 对象具有这些属性--> username、user_type、name、email、password、company_name、company_profile。这种情况下的插入语句是这样的 -->

insert into users (username, user_type, name, email, password, company_name, company_profile) values (?, ?, ?, ?, ?, ?, ?);

那么,如何在可变编号的基础上创建动态插入查询。 POST 请求正文中的属性?

【问题讨论】:

    标签: mysql node.js mysqljs


    【解决方案1】:

    这是由mysqljs 模块为您处理的,因此您无需过度考虑或过度设计它。将插入有效负载作为对象提供,其中键与表字段名称共享相同的命名。无论您提供什么,都将在插入中使用。如果您不提供字段,它将遵循数据库架构中的表默认值(id 将自动填充并增加,如果您以这种方式进行设置,created_attimestamp 或其他类似日期也会如此字段,如果在没有提供值的情况下将字段设置为使用默认值,则将使用该默认值)。

    有关详细信息,请参阅此处的文档: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 注入。根据您的数据库配置、架构、字段类型和您的个人安全策略的具体情况,您在何时何地使用单项与双项的必要性会有所不同,并且需要使用您自己的代码库进行测试。

    【讨论】:

    • 感谢您提供这么好的答案,但是如果我们想使用WHERE 那么mysqljs 模块也会自己处理它吗?
    • 查看我的更新以获取更多上下文和示例,了解如何利用模块的功能支持任意数量的动态元素。
    • 很高兴听到它有帮助!我已经在许多项目中使用这个模块很多年了,并且在此过程中学到了技巧和节省时间的方法。与您通常找到的相比,开发人员文档很棒。话虽如此,该模块具有如此多的功能并且有如此多的实现方法,我发现了解其他人如何在现实世界中日常使用它很有帮助。如果您预测大量的查询吞吐量 - 我建议尽早而不是稍后构建连接池。我发现它在基于节点的微服务和类似应用程序中非常有用。
    • 祝你好运!提问的最佳地点在这里。确保在适用的情况下使用mysqljs 标签,如果我们知道答案,像我这样关注该标签的人将帮助解决问题。如果您想要一个使用池的连接设置的简单示例,我创建了一个 sn-p,您可以在此处用作指南:github.com/dusthaines/mysqljs_setup_snippet/blob/master/app.js
    • 好的,谢谢分享sn-p,这将是一个很大的帮助,不知道该说什么,你帮了我很多。它就像 node js 和 MySQL 的入门包。我会检查你的 GitHub 存储库。谢谢
    【解决方案2】:

    这不是一个好的答案,但它正在工作,所以可以解决这个小技巧,但如果有人知道这一点,请发布答案。

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

    【讨论】:

      猜你喜欢
      • 2011-06-26
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      • 1970-01-01
      • 2015-10-25
      • 2018-12-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多