2

The number of properties in body object is different which is based on a value user_type.

If the user_type is job_seeker then the body object is having these properties --> username, user_type, name, email, password, resume, resume_date_time, salary_expectation. I've created the hard coded insert statement like this -->

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

If the user_type is employer then the body object is having these properties --> username, user_type, name, email, password, company_name, company_profile. Insert statement for this case is this -->

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

So, how to create a dynamic insert query on the basis of varying no. of properties in the body of POST request?

Germa Vinsmoke
  • 3,541
  • 4
  • 24
  • 34
  • If you have json data then you can try code snippet from here: https://stackoverflow.com/a/71236889/8301207 – Fayaz Feb 23 '22 at 12:31

2 Answers2

5

This is handled for you by the mysqljs module so you don't need to overthink it or over engineer it. Provide your insert payload as an object where the keys share the same naming as your table field names. Whatever you provide will be used in the insert. If you do not provide a field it will defer to the table defaults in your database schema (id will auto populate and increment if you've set it up that way, as will created_at, timestamp or other similar date fields, if a field is set to use a default value when no value is provided, that default will be used).

See the documentation here for further details: https://github.com/mysqljs/mysql#escaping-query-values

Below is an example using the two scenarios you provided.

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.

If you structure your POST body properly prior to delivering it to this step in your code, you can save yourself some time and just let it flow through to the query function with no additional work or object constructing or manipulating.

Edit based on comment

If your plan is to include some query parameters you likely want to use an UPDATE rather than an INSERT. Either way we can use this as an example of how to illustrate the dynamic features provided by the mysqljs module.

Every time you use a ?, it is a placeholder that maps to the array index which follows in the function.

In the documentation section I linked, you can see an example where 4 ? map to 4 values provided in an array that follows. You just need to make sure that the order of the values in your array align with the correct order corresponding to their question marks.

If we want to tackle this all in one query with one object, we can just add some complexity to our POST object such that it contains all the info we will need for our query. Using your example, consider the following:

// 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
}

Note: You will see sometimes I use ?? while other times I use ?. This is a feature of the module which provides escaping to prevent SQL injection. Depending on the specifics of your database configuration, architecture, field types, and your personal security policies, the necessity of where and when you use a single vs. a double will vary and will require testing with your own code base.

dusthaines
  • 1,320
  • 1
  • 11
  • 17
  • Thanks for such a nice answer but what if we want to use `WHERE` then also mysqljs module will handle it on its own? – Germa Vinsmoke Jul 22 '19 at 14:01
  • 1
    See my updates for more context and examples on how to support as many dynamic elements as you'd like, where you'd like, leveraging the features of the module. – dusthaines Jul 22 '19 at 16:07
  • Thanks a lot for helping me, that's some quality answer, explained everything related to dynamic part of the query – Germa Vinsmoke Jul 22 '19 at 16:28
  • 1
    Glad to hear it was helpful! I've used this module for many years, on many projects and learned tricks & timesavers along the way. The developer documentation is great compared to what you usually find. That being said the module has so many features and there are so many approaches to implementation, I find it helpful to see how others are using it in the real world day to day. If you predict a high volume of query throughput - I would recommend building in connection pooling sooner rather than later. I've found it quite helpful in node based micro services and similar applications. – dusthaines Jul 22 '19 at 17:24
  • Ah I see, I'm using it for the first time, yeah I was thinking of using connection pooling. Once again thanks for the guidance. Btw, is there any other place where I can ask things related to this in future? – Germa Vinsmoke Jul 22 '19 at 17:30
  • 1
    Good luck! The best place to ask questions is here. Make sure to use the `mysqljs` tag where applicable and people like myself that follow that tag will help with the questions if we know the answers. If you would like a simple example of connection setup using pooling, I've created a snippet you might be able to use as a guide here: https://github.com/dusthaines/mysqljs_setup_snippet/blob/master/app.js – dusthaines Jul 22 '19 at 18:25
  • 1
    Okay, thanks for sharing that snippet, that'll be a great help, don't know what to say, you've helped me a lot. It's like a starter pack for node js and MySQL. I'll check your GitHub repos. Thanks – Germa Vinsmoke Jul 23 '19 at 01:13
2

This is not a good answer but it's working so gonna work around with this little hack but if anyone knows about this then please post an answer.

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);
Germa Vinsmoke
  • 3,541
  • 4
  • 24
  • 34