I'm trying to make a MySQL query to filter data from a table. Effectively what I want to do is:
SELECT data FROM table WHERE column IN ?
The filter is coming from checkboxes in a form on a webpage, so I can pass an array or object fairly easily, but it'll be a varying number of parameters for the IN each time, so I can't us multiple ?. I tried making a for loop to make multiple queries concatenate the arrays that the queries returned, but I ran into scope issues with that. I also tried passing an array directly to the query, but that throws a syntax error. I'm sure there's a straightforward answer to this but I'm not sure how to do it.
Edit: source code added:
Here's where I'm at:
const filterShowQuery = `SELECT sl_Show.showId, sl_Band.BandName,
sl_Show.date, sl_Venue.venueName,
sl_Show.length, sl_Show.attendance, sl_Show.encore FROM sl_Show
JOIN sl_Band on sl_Show.BandID = sl_Band.BandId
JOIN sl_Venue on sl_Show.VenueId = sl_Venue.VenueId
WHERE sl_Band.BandName IN (?)
ORDER BY sl_Band.BandName;`;
Trying to get an array into the ? in WHERE sl_Band.BandName IN
const getShows = (req, res,next) =>{
var {bands, venues} = req.body;
var i = 0; //left over from previous attempt
var data = [];
for (b in bands){
mysql.pool.query(filterShowQuery, bands[b], (err, result) => {
if(err){
console.log('filter band error');
next(err);
return;
}
data = data.concat(result);
console.log(data); //data concatenates property and increases through for loop
})
// same action to be performed with venues once solved
// for (v in venues){
// conditions[i] = venues[v];
// i++;
console.log(data); //data is empty when logging from here or using in res
res.json({rows:data});
}
}
SECURITY WARNING!
I must to say: NEVER, NEVER PASS DATA DIRECTLY TO YOUR SQL!
If you don't know why, just google for SQL Injection. There are lots of examples on how it is done, how easily it can be done, and how to protect your application from this sort of attack.
You should always parametrize your queries. But in the very rare case which you really need to insert data concatenating a string into your sql, validate it before.
(E.g.) If it's a number, than use a Regex or some helper method to check if the value you are inserting into your SQL String is really and only a number and nothing else.
But aside that, you did not provide any source code, so it's really hard to give any help before you do that.
Related
I'm creating a dynamic query in postgresql to filter a resultset.
I pass the parameters in the URL, an example is:
http://www.myurl.com/search?query=hello+word&sortorder=relevance&date=week&categories=cat1,cat2
The problem is, when a user selects a lot of categories (and other parameters that aren't included in the example URL), the URL will be very, very long. I'm using UUIDv4 for ID's so a lot of UUIDv4's are in the URL, separated by comma's.
Is it a better idea to do this with a POST request?
EDIT:
I'm using validator to check if the incoming parameters are valid UUIDv4 (or numbers, ... whatever I need for that parameter to be).
I'm using node-postgres to execute queries. This supports prepared statements, but I have NO CLUE how to use prepared statements with dynamic queries.
My SELECT code now looks like this (simplified):
const { featured, order } = req.body;
// featured
let featuredQuery = '';
if (featured !== undefined && validator.isBoolean(featured.toString())) {
let featuredQuery = ` AND featured = ${featured}`;
}
// order
let orderQuery = 'timestamp DESC';
if (order !== undefined) {
switch (order) {
default:
case 'date':
orderQuery = 'timestamp DESC';
break;
case 'user_id':
orderQuery = 'user_id DESC';
break;
}
}
const query = `
SELECT
name,
description
FROM
users
WHERE
active = true
${featuredQuery}
ORDER BY
${orderQuery}
`;
As you can see, I'm not passing prepared statements ($1, $2, ...) to the query but I'm using template literals. I have NO CLUE how to use prepared statements to add/delete where clauses.
Is there a safer way to do this?
EDIT 2: parameters are not containing sensitive information. I pass the user ID in the authorization header as a JWT.
If you're fetching the contents of your parameter-laden URL using a program, not a browser, long GET URLs don't matter very much. (In browsers they're ugly.) For best results, and less testing burden on various legacy proxy servers etc, do your best to keep your URL length to 2000 octets or less. (Payload size for POST requests has no such limitation.)
Beware that URLs get logged. So, if your parameters carry any sensitive information you should consider using POST rather than GET. Otherwise your users' sensitive information will land in your web server logs, presenting a juicy target for cybercreeps.
And, please please read up on SQL injection. Please please sanitize your incoming parameters before handing them off to your database server. Remember that cybercreeps can (and will) hit your URL from their malicious programs and try all sorts of combinations trying to break in.
I want to access resources from a SQLite database table. I have one table for accounts, one for movies and one for reviews. The reviews-table is constructed like this:
CREATE TABLE IF NOT EXISTS reviews (
id INTEGER PRIMARY KEY,
authorId INTEGER,
movieId INTEGER,
review TEXT,
rating INTEGER,
FOREIGN KEY('authorId') REFERENCES 'accounts'('id'),
FOREIGN KEY('movieId') REFERENCES 'movies'('id')
)
What I want to do is that I want to be able to get all reviews, made by one author. But I also want to be able to get all reviews, made for the same movie. Below is my code for getting all reviews made by the same user/author. The code looks the same when getting the reviews based on the movie, with a few changes.
Both of them does what I want them to do. But of course only the one written first in the file are running.
const authorId = request.params.authorId;
const query = "SELECT * FROM reviews WHERE authorId = ?";
const values = [authorId];
db.all(query, values, function (error, review) {
if (error) {
response.status(500).end();
} else if (!review) {
response.status(404).end();
} else {
response.status(200).json(review);
}
});
});
The url will look the same no matter which of them I want running; http://localhost:3000/reviews/3. How can I differentiate the url so that they know which one should run?
I have tried to experiment with query strings, but I'm not sure how that works, and after hours of searching for something that worked on my code, I gave up.
I have also been thinking about using something like
app.use(function (request, response, next) {
if (request.method == "GET" && request.uri == "/reviews/:authorId") {
response.send("Hello World");
} else {
next;
}
});
This didn't work, and it didn't work if I tried to remove ":authorId" from the url either. The page just keeps loading.
So how do I solve this?
The most dynamic would be a single route /reviews and use the query string with the params like ?author=123 or ?movie=123, they can be combined like ?author=123&movie=123. As you want to return JSON the code will be used via API, so the pretty path is usually not as important as when it is a web-url. To make the implementation effective, most people use a function where you can drop the query object in and get the where-clause, or use an ORM.
In express, when you have routers like '/reviews/:authorId' and then '/reviews/:movieId', then the second one will never be called, because the first one will always match. That is something to be careful about when organizing your express routes.
I am checking if a combination of child values exists in my DB.
This works but can't get the proper message to be displayed in the console.
the correct console message is displayed in both else statements. The one that is not being displayed properly is the console.log('yes').
Or actually it is displayed but always followed by aconsole.log('no') and I have no idea why
There is however a match found because the correct data is shown in console.log(details); console.log(snapshot.key);
FBSearch: function(){
var T1 = this
var T2 = this
var T3 = this
var ref = firebase.database().ref("flights");
ref
.orderByChild('date')
.equalTo(T2.flight.dat)
.on('child_added', function(snapshot) {
var details = snapshot.val();
if (details.flight == T1.flight.flt) {
if(details.origin == T3.flight.org){
console.log(details);
console.log(snapshot.key);
console.log('yes')
} else {
console.log('no')
}
} else {
console.log('no')
}
})
}
The desired outcome is a success message when a match is found
Not sure if this is the answer to your question, but something you might want to consider...
Right now you're reading all flights of the specific date, in an effort to check if one of them exists. This is suboptimal, and can waste lot of your users' bandwidth. Ideally a yes/no question like that should require you to pass in the criteria, and get a minimal yes/no type answer.
While the Firebase Realtime Database doesn't support exists() queries, and can't query on multiple conditions, you can make significant improvements by adding a special property to your data to support this query.
As far as I can see, you're filtering on three properties: date, flight, and origin. I recommend adding an extra property to all flights that combines the values of these properties into a single value. Let's call this property "origin_date_flight".
With that property in place you can run the following query to check for the existence of a certain combination:
ref
.orderByChild('origin_date_flight')
.equalTo(`${T3.flight.org}_${T2.flight.date}_${T1.flight.flt}`)
.limitToFirst(1)
.once('value', function(snapshot) {
if (snapshot.exists()) {
console.log('yes')
} else {
console.log('no')
}
})
The main changes here:
The query uses a composite property as a sort-of index, which allows it to query for the specific combination you're looking for.
The query uses limitToFirst(1). Since you're only looking to see if a value exists, there's no need to retrieve multiple results (if those exist).
The query uses once("value", which allows it to check for both existence and non-existence in a single callback. The child_added event only fired if a match exists, so can't be used to detect non-existence.
And as a bonus, this new property also allow you to for example get all flights out of Amsterdam today:
ref
.orderByChild('origin_date_flight')
.startAt(`AMS_20190728_${T2.flight.date}_`)
.endAt(`AMS_20190728_${T2.flight.date}~`)
.once('value', function(snapshot) {
snapshot.forEach(function(flightSnapshot) {
console.log(flightSnapshot.key+": "+flightSnapshot.child("flt").getValue());
})
})
Also see:
Query based on multiple where clauses in Firebase
I was searching for an easy and simple database for a little highscore system for a some games I'm developing in javascript.
I saw Orchestrate.io in github's student developer pack. I found a suitable drivermodule nodejs orchestrate and have integrated them.
The problem comes with querying orchestrate for my data. I have managed saving scores and querying them with db.list('collection'), but this seems to not responding with all data. It appered to me that some values are not returned.
I read about the db.search('collection','query') function. But I don't really understand how I could return all data because I don't want to query in a specific way.
My objects are as simple as follows:
{"name":"Jack","score":1337}
As I understand, one has to send a key, when putting such values to an orchestrate-collection. But I'd like to query the whole collection and get the values in a descendant order in regard to the score.
As for now I end up sorting the result on the client-side.
I hope you guys can give me some hints for a query that can sort for specific values!
You have the option to use a SearchBuilder
db.newSearchBuilder() //Build a search object
.collection('collection') //Set the collection to be searched
.sort(score, 'desc') //Set the order of the results
.query("*") //Empty search
.then(function (res) { //Callback function for results
//Do something with the results
})
Source
By default, .list uses a pagination limit of 10. You can either increase that, e.g.:
db.list('collection', { limit: 100 })
Or use .links, .links.next (from the docs):
db.list('collection', { limit: 10 })
.then(function (page1) {
// Got First Page
if (page1.links && page1.links.next) {
page1.links.next.get().then(function (page2) {
// Got Second Page
})
}
})
Can someone show me a web SQL select query that returns the results as an object rather than alerting or logging to the console.
I want to centralize my select queries rather than repeating the select / execute and process results code in the specific functions.
If we presume that the question relates to the API required under Web SQL to execute the query and obtain a result set you can proceed as shown below. I've not given much detail as the question is a tad vague and shows little evidence of homework...
Initiate a readTransaction (you did say 'query' so I'll presume "select") on an open database:
db.readTransaction(onStartTransaction); // less locking overhead with a readTransaction
The onStartTransaction function looks like this:
function onStartTransaction(tx) {
tx.executeSql(sql, params, onExecuteSqlOk, onExecuteSqlFail);
}
Just pass your sql and a [] for params if you don't need any.
Your results will be returned to your 'onExecuteSqlOk' function:
function onExecuteSqlOk(tx, result) {
//
// tx: an SqlTransaction object
// results: an SqlResultSet object
//
The goodies are in the SqlResultSet object.
it has a structure with a 'rows' property. Each row contains the fields specified in the sql select statement.
var len = results.rows.length; // how many rows did we get
var firstRow = results.rows.item(0);
Thus you get an "object" back as the results from a Web Sql query. Note that the api shown is asynchronous so you will probably want to use a further callback function....