Creating MySQL queries programmatically using data stored in a JSON object

Is it possible to construct a MySQL query dynamically from a JSON object with potentially empty values?

For instance, starting with an object like this:

{
  "a": 1
  "b": ""
  "c": "foo"
}

we want to generate a query like the following (ignoring the empty value for "b") :

SELECT * FROM db.table
WHERE a = 1
AND c = "foo"

or

SELECT * FROM db.table
WHERE a = 1
AND b = ????
AND c = "foo"

Edit : It may be a duplicate question. However, I was hoping for a more SQL-oriented approach, possibly involving variables and IF statements.

Edit 2 : I have discovered a method (working in node.js API but should work similarly in other languages) :

const jsonObj = {
"a": 1,
"b": "",
"c": "foo"
}
const query = `
SELECT * FROM db.table
WHERE
IF('${jsonObj.a}' != '', a = '${jsonObj.a}', 1=1)
AND 
IF('${jsonObj.b}' != '', b = '${jsonObj.b}', 1=1)
AND 
IF('${jsonObj.c}' != '', c = '${jsonObj.c}', 1=1)
`

Please note that this code is not ready for use as-is; adjustments are needed to address potential injection vulnerabilities.

Answer №1

Please Note: It is important to be aware that this strategy is susceptible to SQL Injection Attacks. To prevent this, it is crucial to escape the values properly, preferably by utilizing prepared queries. Without sufficient understanding of your database client, providing specific guidance on how to do this is challenging.

Additionally: I highly recommend implementing a whitelist for allowed columns and only allowing column keys within the whitelist to be utilized in your query. Below, you will find an example incorporating a whitelist to illustrate this concept.

Below is an MVP designed to handle a dynamic object and construct a SQL statement based on your specifications:

const obj = {
  "a": 1,
  "b": "",
  "c": "foo",
  "bad": "disallowed"
}

// Example of how to use a whitelist
const whitelist = ['a', 'c'];

// Initialize an empty array to store the WHERE conditions
let where = [];

// Iterate through each key / value in the object
Object.keys(obj).forEach(function (key) {
    // If the key is not whitelisted, do not proceed
    if ( ! whitelist.includes(key) ) {
        return;
    }

    // Do not proceed if the value is an empty string
    if ( '' === obj[key] ) {
        return;
    }

    // Add the clause to the array of conditions if all conditions are met
    where.push(`\`${key}\` = "${obj[key]}"`);
});

// Convert the array of conditions into a string of AND clauses
where = where.join(' AND ');

// Prepend the WHERE keyword if there is a WHERE string
if (where) {
    where = `WHERE ${where}`;
}

const sql = `SELECT * FROM table ${where}`;

console.log(sql);
// SELECT * FROM table WHERE `a` = "1" AND `c` = "foo"

NOTES:

  1. It is important to mention that providing any form of character escaping goes beyond the scope of this question / answer. This method may fail if values include double-quote characters (e.g., ")
  2. Moreover, offering a solution to determine if the value is numeric and refrain from enclosing it in quotes in the query exceeds the bounds of this question / answer. Nonetheless, many databases can handle a numeric value enclosed in quotes successfully.

Answer №2

Discover the power of a versatile function designed to handle complex queries

function createQueryParams(params) {
    const constraints = [];
    const data = [];
    Object.keys(params).forEach((item) => {
        if (!params[item] || params[item] == "") {
            return;
        }
        if (Array.isArray(params[item])) {
            constraints.push(`${item} in (?)`);
            data.push(params[item]);
        } else if (typeof params[item] === "string" && params[item].indexOf(",") > -1) {
            constraints.push(`${item} in (?)`);
            data.push(params[item].split(","));
        } else if (params[item] instanceof RegExp) {
            constraints.push(`${item} REGEXP ?`);
            data.push(params[item]);
        } else if (params[item] && typeof params[item] === "object") {
            Object.keys(params[item]).forEach((value) => {
                if (value === "$gte") {
                    constraints.push(`${item} >= ?`);
                    data.push(params[item][value]);
                } else if (value === "$lte") {
                    constraints.push(`${item} <= ?`);
                    data.push(params[item][value]);
                } else if (value === "$gt") {
                    constraints.push(`${item} > ?`);
                    data.push(params[item][value]);
                } else if (value === "$lt") {
                    constraints.push(`${item} < ?`);
                    data.push(params[item][value]);
                } else if (value === "$like") {
                    if (Array.isArray(params[item][value])) {
                        const localConstraints = [];
                        params[item][value].forEach((likeValues) => {
                            localConstraints.push(`${item} LIKE ?`);
                            data.push(`%${likeValues}%`);
                        });
                        constraints.push(`(${localConstraints.join(" OR ")})`);
                    } else if (typeof params[item][value] === "string" && params[item][value].indexOf(",") > -1) {
                        const localConstraints = [];
                        params[item][value] = params[item][value].split(",");
                        params[item][value].forEach((likeValues) => {
                            localConstraints.push(`${item} LIKE ?`);
                            data.push(`%${likeValues}%`);
                        });
                        constraints.push(`(${localConstraints.join(" OR ")})`);
                    } else {
                        constraints.push(`${item} LIKE ?`);
                        data.push(`%${params[item][value]}%`);
                    }
                }
            });
        } else {
            constraints.push(`${item} = ?`);
            data.push(params[item]);
        }
    });
    return { constraints, data };
}

const input = {
    userId: 1,
    company: ["google", "microsoft"],
    username: { $like: "Test" },
    name: { $like: [ "Test1", "Test2" ] },
    age: { $gt: 10 }
}
const queryData = createQueryParams(input);
console.log("SELECT * FROM user WHERE ", queryData.constraints.join(" and "));
console.log(queryData.data);

This multifunctional tool provides a structured approach to escape characters in queries effectively. By using this method, you can safeguard against SQL injection attacks. It is recommended for users utilizing the mysql package

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Blend field and JavaScript functions while retrieving data from MongoDB

Take a look at this information: { "creation_date" : ISODate("2015-02-10T03:00:00.000Z"), "days_of_validity": 10 } I need to find all documents where "creation_date" is less than today - "days_of_validity" This is what I have come up with so far: doc ...

Vue Framework 7 incorporates a validation feature that ensures successful outcomes

In my current project using Framework7 Vue with version 4.4.3, I am facing a challenge in validating a form upon submission. I came across this helpful code snippet: $$('.save').on('click', function(e){ e.preventDefault(); if ...

Arranging website elements to conform to a compact grid system

Recently, I've been brainstorming a unique concept for a website layout that involves a background composed of tiny color-shifting squares, each measuring about 10px. The challenge I'm facing is aligning the elements on the page with this grid, a ...

What is the best way to place two stacked buttons side by side in an inline format?

I am trying to rearrange the layout of a bootstrap modal that includes two multiple select elements and two buttons. My goal is to have all controls inline, with the buttons stacked on top of each other. Here's an example of what I'm aiming for: ...

Is there a dependable resource for mastering Protractor along with the Jasmine Framework in Eclipse using JavaScript?

Starting a new role at my organization where I will be testing Angular JS applications. Can anyone recommend a good website for learning PROTRACTOR with JAVASCRIPT using the JASMINE Framework? (Would prefer if it includes guidance on Eclipse IDE) Thank yo ...

Uploading directly to AWS S3: SignatureDoesNotMatch error specifically for Internet Explorer users

My process involves using Amazon Web Service S3 for uploading and storing files. I create a pre-signed URL using the AWS SDK for Node.js on the server-side to enable direct file uploads from the browser through this signature URL. The Process On the serv ...

Error: The use of "let" as a lexically bound identifier is not permitted

Currently working with vue.js and encountering the error message "Uncaught SyntaxError: let is disallowed as a lexically bound name". When trying to troubleshoot, I'm faced with a blank screen and this error appearing in the console. I've search ...

Converting a JavaScript variable into PHP using ajax: A comprehensive guide

Can someone please help me troubleshoot this code for passing a JavaScript variable to PHP? It doesn't seem to be working properly. I want to extract the value of an ID from JavaScript and send it over to PHP. <!DOCTYPE html> <html> ...

Utilize Angular components in TypeScript to effectively manage errors within forms

I am currently developing a form in Angular/Typescript with more than 10 fields, and I want to streamline error management without redundancy in my HTML code. Here is an example of the form structure : <form [formGroup]="myForm"> <label&g ...

Retrieve data from a MongoDB collection based on a specific index field

I am looking to extract only the "thetext" field from a specific index in my database when the value of "comment_count" is 1. This is the query I have tried: db.getCollection('mongotesi').find({},{'bug.long_desc.1.thetext':'1&apo ...

html interactive/expandable tree

I've come across this code which generates an HTML tree, but I'm facing an issue where the tree expands every time I refresh the page. What I want to achieve is to have certain branches expanded and others collapsed when the page is opened, depe ...

json array: Tips for adding elements to a new array

In order to achieve my goal, I am looking to create a JSON array structure similar to the one shown below: var args = [{ name: 'test', value: 1 }, { key: 'test2', value: 2}]; How can I modify the code snippet provided below to generat ...

What is the best way to display table rows for a specified date range?

I am working with a table and need to display only the rows that fall between two specific dates. <table id ="Table"> <thead> <tr> <th>Date</th> <th>Name</th> <th>Desc</th> </tr> </thead> ...

The aspect of a composite key that automatically increments

At the moment, my composite-primary key is a combination of (user, id). John Smith is my current user and there are approximately 30 rows related to him, causing the id to automatically increment with each new entry. But if I were to introduce a new use ...

React - assigning a value to an input using JavaScript does not fire the 'onChange' event

In my React application with version 15.4.2, I am facing an issue where updating the value of a text input field using JavaScript does not trigger the associated onChange event listener. Despite the content being correctly updated, the handler is not being ...

What are some techniques for utilizing jq to extract a specific field from a terraform blueprint in order to display the resources that have been modified or updated?

Is there a way to get a quick summary of changes in a Terraform plan instead of the detailed output? I believe it can be achieved with Terraform plan and jq. Here's what I have tried: To generate a plan, I use this command: terraform plan -out=tfpl ...

What is the best way to exclude certain values from Objects in Javascript?

Imagine having an object structured like this: "errors": { "name": { "name": "ValidatorError", "message": "Minimum length 6 characters.", "propert ...

Is there a way to conceal a div element if the user is not logged in?

I have been enlisted to assist my friend with a project involving his website. Within the site, there is a checkbox that prompts the display of a div when selected. I believe it would be more effective for this checkbox to only be visible to users who are ...

Exploring ways to retrieve the parent property name within System.Text.Json.Serialization.JsonConverter

Working with a 3rd Party API that provides data in the following format: { "dynamicFields": { "prop1": "val1", "prop2": "val2", "prop3": "val3" }, // otherFields ... } ...

Guide on how to clear and upload personalized information to Stormpath

After receiving JSON data from my client, I am looking to store it in Stormpath's custom data using node.js with express.js: I have set up a basic post route: app.post('/post', stormpath.loginRequired, function(req, res){ var data = req.b ...