I has simple function in nodejs, which add result to MYSQL. But result is coming in array, and i can't correctly add this data to the table.
My functions:
function getPreviousGames() {
const previousGames = [];
let gameHash = generateHash(crashHash);
for (let i = 0; i < 1; i++) {
const gameResult = crashPointFromHash(gameHash);
previousGames.push({ gameHash, gameResult });
gameHash = generateHash(gameHash);
}
return previousGames;
}
function verifyCrash() {
const gameResult = crashPointFromHash(crashHash);
const previousHundredGames = getPreviousGames();
for (let i = 0; i < 1; i++) {
var sql = "INSERT INTO `admin_dev`.`crash_numbers` (`id`, `hash`, `multiplier`, `status`, `created_at`, `updated_at`) VALUES (NULL, '" + previousHundredGames(gameHash) + "', '" + gameResult + "', '0', now(), now());";
connection.query(sql, function (err, result) {
if (err) throw err;
console.log("Success!");
});
}
return { gameResult, previousHundredGames };
}
And i received result:
{
previousHundredGames: [
{
gameHash: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
gameResult: 2.52
}
]
}
And i can't correcly add this received data to mysql table.
I need add from previousHundredGames value gameHash to hash column, and gameResult value to multiplier column.
How i can correctly made it?
If you are using a query, it is as simple as building an INSERT query.
//Start the query
let query= 'INSER INTO (hash, gameResult) VALUES ';
//Add multiple rows from the array
for (let aGame of previousGames)
query+= `( "${aGame.gameHash}", ${aGame.gameResult}), `
//Remove the last comma
query= queryBuilder.substring(0, queryBuilder.length - 1)
Here is documentation on inserting multiple rows in a single query.
https://www.mysqltutorial.org/mysql-insert-multiple-rows/
Related
First of all, i'm new in JS. I have a function that possibly can use multiple requests to get the final data. How can i do this in the right way? In this example participants won't pushed to the dialogs array because it's in async call.
function getDialogs(token, callback) {
//getting user id
con.query("SELECT user_id FROM users_tokens WHERE user_token = '" + token + "'", function(error, results) {
if (error) {
throw error;
}
var userId = results[0].user_id;
//getting all conversation
con.query("SELECT cc.id as conversation_id, cc.type FROM chat_conversations cc INNER JOIN chat_participants cp ON cc.id = cp.conversation_id WHERE cp.user_id = " + userId + " GROUP BY cc.id", function (error, results) {
if (error) {
throw error;
}
var dialogs = [];
for (let i = 0; i < results.length; i++) {
var dialog = {id: results[i].conversation_id};
//getting chat participants
con.query("SELECT user_id FROM chat_participants WHERE conversation_id = " + results[i].conversation_id + " AND user_id != " + userId, function (error, results) {
var participants = [];
for (let j = 0; j< results.length; j++) {
participants.push(results[j].user_id);
}
dialogs[participants] = participants;
});
dialogs.push(dialog);
}
callback(dialogs);
});
});
}
Technically you can use a single request like this
SELECT user_id FROM chat_participants WHERE conversation_id IN (
SELECT
cc.id as conversation_id,
cc.type
FROM
chat_conversations cc
INNER JOIN chat_participants cp ON cc.id = cp.conversation_id
WHERE
cp.user_id IN (
SELECT
user_id
FROM
users_tokens
WHERE
user_token = "TOKEN"
)
GROUP BY
cc.id
)
but there are a few problems with this approach as well.
First of all, it seems like you are only using the user_id of your first row, so please use LIMIT 1 in such cases.
Second of all, it seems like user_id won't ever have a duplicate, so make it a primary key.
Third of all, don't concat your token, node mysql supports having placeholders using ? in your query, like this:
con.query("SELECT * FROM ? WHERE user_id = ?", ["table_name", "userid"])
Fourth of all, promisify your requests so you don't have a callback hell, do something like:
function promiseRequest(query, placeholders) {
return new Promise((res, rej) => {
con.query(query, placeholders, (err, data) => {
if (err) rej(err);
res(data);
});
});
}
I'm using nodejs-mysql module to do query in node.js recently, and in my working case I could only use the parameter-binding syntax like:
SELECT * FROM table WHERE name = ?
Now I want to build dynamic sql with these ? OR ?? parameters. Assume that I have 2 conditions(name and age) which either of them could be null (if user doesn't provide it),
So I want to build MySQL in 3 cases:
only name=Bob: SELECT * FROM table WHERE name = 'Bob'
only age=40: SELECT * FROM table WHERE age > 40
both: SELECT * FROM table WHERE name = 'Bob' AND age > 40
I know it's easy if you build the query on your own, but how can I achieve it when using placeholders which can only bind field or values ?
In document of nodejs-mysql, placeholder ? only stands for values and ?? stands for fields:
https://github.com/felixge/node-mysql/#escaping-query-values
https://github.com/felixge/node-mysql/#escaping-query-identifiers
My first thinking of solution is to insert query piece by using these placeholders, but it comes to failure because both ? and ?? will escape my query piece, and my query will be executed incorrectly.
My code so far is as below, which I'm defenitly sure it's not correct because query piece has been escaped:
// achieve paramters from url request
var condition = {};
if(params.name)condition["name"] = ["LIKE", "%" + params.name + "%"];
if(params.age)condition["age"] = parseInt(params.age, 10);
//build query
var sqlPiece = buildQuery(condition);
//try to replace ? with query
var sql = 'SELECT * FROM table WHERE ?';
connection.query(sql, sqlPiece, function(err, results) {
// do things
});
// my own query build function to proceed conditions
function buildQuery(condition) {
var conditionArray = [];
for(var field in condition){
var con = condition[field];
if(con !== undefined){
field = arguments[1] ? arguments[1] + "." + field : field;
var subCondition;
if(con instanceof Array) {
subCondition = field + " " + con[0] + " " + wrapString(con[1]);
}else{
subCondition = field + " = " + wrapString(con);
}
conditionArray.push(subCondition);
}
}
return conditionArray.length > 0 ? conditionArray.join(" AND ") : "1";
}
//wrap string value
function wrapString(value){
return typeof value === "string" ? "'" + value + "'" : value;
}
So is there any way I can fix this problem?
Update
Thanks to Jordan's Offer, it's working, but :
I know building query by string concat is very good, but in my case I can't use that, because I'm using some middleware or handle mysql and controller, so what I can do is to define interface, which is a sql string with placeholders. So, the interface string is predefined before, and I can't modify it during my controller function.
You're off to a really good start, but you may have been overthinking it a bit. The trick is to build a query with placeholders (?) as a string and simultaneously build an array of values.
So, if you have params = { name: 'foo', age: 40 }, you want to build the following objects:
where = 'name LIKE ? AND age = ?';
values = [ '%foo%', 40 ];
If you only have { name: 'foo' }, you'll build these instead:
where = 'name LIKE ?';
values = [ '%foo%' ];
Either way, you can use those objects directly in the query method, i.e.:
var sql = 'SELECT * FROM table WHERE ' + where;
connection.query(sql, values, function...);
How do we build those objects, then? In fact, the code is really similar to your buildQuery function, but less complex.
function buildConditions(params) {
var conditions = [];
var values = [];
var conditionsStr;
if (typeof params.name !== 'undefined') {
conditions.push("name LIKE ?");
values.push("%" + params.name + "%");
}
if (typeof params.age !== 'undefined') {
conditions.push("age = ?");
values.push(parseInt(params.age));
}
return {
where: conditions.length ?
conditions.join(' AND ') : '1',
values: values
};
}
var conditions = buildConditions(params);
var sql = 'SELECT * FROM table WHERE ' + conditions.where;
connection.query(sql, conditions.values, function(err, results) {
// do things
});
For Inserting into MYSQL like DB:
function generateInsertQuery(data, tableName) {
let part1 = `INSERT INTO ${tableName} (`;
let part2 = ")",
part3 = "VALUES (",
part4 = ")";
let tableKeys = "",
tableValues = "";
for (let key in data) {
tableKeys += `${key},`;
tableValues += `'${data[key]}',`
}
tableKeys = tableKeys.slice(0, -1);
tableValues = tableValues.slice(0, -1);
let query = `${part1}${tableKeys}${part2} ${part3}${tableValues}${part4}`;
return query;
}
generateInsertQuery({name: "Sam", tel: 09090909, email: "address#domain.com"}, "Person")
Output:
INSERT INTO Person (name,tel,email) VALUES ('Sam','9090909','address#domain.com');
Code Snippet for Update query:
function generateUpdateQuery(data, tableName, clauseKey, clauseValue) {
let part1 = `UPDATE ${tableName} SET`;
let part2 = `WHERE ${clauseKey} = ${clauseValue};`; //Add any number of filter clause statements here
let updateString = "";
for (let key in data) {
updateString += `${key} = '${data[key]}',`;
}
updateString = updateString.slice(0, -1);
let query = `${part1} ${updateString} ${part2}`;
return query;
}
generateUpdateQuery({
name: "Tanjiro",
tel: 77777777,
email: "tanjiro#demonslayer.com"
}, "Person", "ID", 111);
Output:
UPDATE Person SET name = 'Tanjiro',tel = '77777777',email = 'tanjiro#demonslayer.com' WHERE ID = 111;
I modify your code #Jordan-Running
describe("Test generateFilterQuery", () => {
it("Query filter with params", () => {
let params = []
params.push(Query.generateParams("title", "%_%", "Coding"))
params.push(Query.generateParams("published", "=", true))
console.log(Query.generateFilterQuery(params))
});
});
const qInclude = require('./QueryInclude');
exports.generateParams = (name, eq, value) => {
return {
name: name,
eq: eq, // %_%, %_, _%, =, >, <, !=,
value: value
}
}
exports.generateFilterQuery = (params) => {
let conditions, values = []
let conditionsStr;
if (params.length == 0) {
return false
}
[conditions, values] = qInclude.queryCondition(params)
let build = {
where: conditions.length ?
conditions.join(' AND ') : '1',
values: values
};
let query = 'SELECT * FROM table WHERE ' + build.where;
return [query, build.values]
}
exports.queryCondition = (params) => {
var conditions = [];
var values = [];
params.forEach(item => {
switch (item.eq) {
case '=': {
conditions.push(item.name + " = ?");
values.push(item.value);
break;
}
case '!=': {
conditions.push(item.name + " != ?");
values.push(item.value);
break;
}
case '<': {
conditions.push(item.name + " < ?");
values.push(item.value);
break;
}
case '>': {
conditions.push(item.name + " > ?");
values.push(item.value);
break;
}
case '%_%': {
conditions.push(item.name + " LIKE ?");
values.push("%" + item.value + "%");
break;
}
case '%_': {
conditions.push(item.name + " LIKE ?");
values.push("%" + item.value);
break;
}
case '_%': {
conditions.push(item.name + " LIKE ?");
values.push(item.value + "%");
break;
}
}
});
return [conditions, values]
}
I want to insert the stockid's in the database in a different row and I am using a for loop. I also want to know the last iteration, but because of the async of javascript I am having trouble getting this to work. The current output is that j only increasing by 1 and print 4 times. I will appreciate any assistance or recommendation. Thanks.
var order_id = 827283383;
var stockid = [1,2,3,4];
for(i = 0; i < stockid.length; i++) {
db.query("insert into order_detail( order_id, stock_id) values ('" + order_id + "','" + stockid[i] + "') ;", function (err, rs) {
var j = 0;
if (err) {
console.log(err);
}
else{
j++; // aimed to use as a counter
console.log(j);
}
if(j < stockid.length-1){ //aimed to get last iteration
console.log('This is the last row');
}
});
}
Only one output return when the data is select in then. code below:
const query = promisify(db.query.bind(db));
Promise.all(stockid.map(id => query("insert into order_detail( order_id, stock_id) values ('" + order_id + "','" + id + "') ;")))
.then(
db.query('select *, order_detail.order_id as orderid from sodiq_business.order_detail join sodiq_business.order on sodiq_business.order.order_id = sodiq_business.order_detail.order_id join sodiq_business.stock on sodiq_business.stock.stock_id = sodiq_business.order_detail.stock_id join sodiq_business.customer on sodiq_business.customer.id = sodiq_business.stock.seller_id join sodiq_business.product on sodiq_business.product.prod_id = sodiq_business.stock.prod_id where order_detail.order_id = ?',[order_id], function (err, rs) {
if (err) {
console.log(err);
}
else{
console.log(rs)
})
As mentioned by #Tapler in the comment, your j sets to 0 in every iteration. Make it like
var order_id = 827283383;
var stockid = [1,2,3,4];
var j = 0;
for(i = 0; i < stockid.length; i++) {
db.query(`insert into order_detail( order_id, stock_id) values (${order_id},${stockid[i]})`, function (err, rs) {
if (err) {
console.log(err);
}
else{
j++; // aimed to use as a counter
console.log(j);
}
if(j < stockid.length-1){ //aimed to get last iteration
console.log('This is the last row');
}
});
}
Also read about Prepared statements and SQL Injection to avoid attacks on the database. This is very much prone to database attacks.
I'd suggest you to promisify db.query:
const { promisify } = require('util');
const query = promisify(db.query.bind(db));
Promise.all(stockid.map(id => query("insert into order_detail( order_id, stock_id) values ('" + order_id + "','" + id + "') ;")))
.then(console.log)
.catch(console.error);
I have a for loop going through a JSON array - with help from this stack question
Whilst looping the script does the following:
- Does the JSON item exist in the tables?
- if yes
- Is the data different?
- if yes
- Update
- if no
- Do nothing
- if no
-insert into database
I found this question which allowed me to query on each for loop so I am able to get the names from the JSON and query them correctly :
for(var i=0; i<content.prices.length; i++) {
var price = content.prices[i].price
var itemName = content.prices[i].market_hash_name;
var q = "SELECT * FROM prices WHERE item = ?";
(function() {
var iNameCopy = itemName;
var priceCopy = price;
connection.query(q, iNameCopy, function (err, results) {
if (err) throw err;
if(results.length === 1) {
logger.info(iNameCopy + " does exist");
}
else if (results.length === 0){
logger.info(iNameCopy + " does not exist");
}
});
}());
}
Moving onto adding the if statement inside results.length === 1
for(var i=0; i<content.prices.length; i++) {
var price = content.prices[i].price
var itemName = content.prices[i].market_hash_name;
var q = "SELECT * FROM prices WHERE item = ?";
(function() {
var iNameCopy = itemName;
var priceCopy = price;
connection.query(q, iNameCopy, function (err, results) {
if (err) throw err;
if(results.length === 1) {
if(parseFloat(results[0].current_price) != parseFloat(priceCopy)) {
logger.info(iNameCopy + " does exist with old price: " + results[0].current_price + " and new price: " + priceCopy);
}
}
else if (results.length === 0){
logger.info(iNameCopy + " does not exist");
}
});
}());
}
Again this is still working.
Now finally replacing those loggers with new sql queries is where the code stumbles. The for loop runs as if I keep the loggers they display however the sql query loggers do not display:
I tried both this way I found from the other stack question and without wrapping it in a function but neither worked. Any suggestions?
for(var i=0; i<content.prices.length; i++) {
var price = content.prices[i].price
var itemName = content.prices[i].market_hash_name;
var q = "SELECT * FROM prices WHERE item = ?";
(function() {
var iNameCopy = itemName;
var priceCopy = price;
connection.query(q, iNameCopy, function (err, results) {
if (err) throw err;
if(results.length === 1) {
if(parseFloat(results[0].current_price) != parseFloat(priceCopy)) {
var sql2="UPDATE `prices` SET `current_price` = ?, `timeStamp` = ? WHERE `item` = ?";
(function() {
var iNameCopy2 = iNameCopy
var priceCopy2 = priceCopy
connection.query(sql2, [priceCopy2, 'Now()', iNameCopy2], function(err,results){
logger.info("UPDATE: " + iNameCopy2 + ' has been updated with price ' + priceCopy2);
});
}());
}
}
else if (results.length === 0){
var sql3="INSERT INTO `prices` (`item`, `current_price`, `timeStamp`) VALUES (?, ?, ?)";
(function() {
var iNameCopy3 = iNameCopy
var priceCopy3 = priceCopy
connection.query(sql3, [iNameCopy3, priceCopy3, 'Now()'], function(err,results){
logger.info("INSERT: " + iNameCopy3 + ' has been added with price ' + priceCopy3);
});
}());
}
});
}());
}
note: I have my database connection on the outside of the for loop:
var connection = mysql.createConnection(db_access);
connection.connect(function(err){
if(err){
logger.error('Error connecting to Db');
return;
}
});
I think something similar to this has been asked before but I cant seem to figure it out. I have two arrays from an SQL database in my cordova app. Is it possible to combine these two arrays and order by the best match to the search query.
In my app I have a search function that searches multiple local tables and orders by the best match. This works fine
SQL Query Example:
tx.executeSql("SELECT * FROM contacts WHERE f_name LIKE ? ORDER BY (CASE WHEN f_name = ? THEN 1 WHEN f_name LIKE ? THEN 2 ELSE 3 END), f_name ",["%" + query + "%", query, query + "%"],onSuccess, onError);
This process is repeated and different arrays are created for the the different tables being searched.
I am left with 2 tables one for users and one for message content. After the SQL queries have run the call back function then sorts all the results into 1 array:
var allResults = [];
// create an array of all
for(var x = 0; x < allChatSearchResults.users.length; x++){
var result = allChatSearchResults.users[x];
result['type'] = 'user';
allResults[allResults.length] = result;
}
for(var x = 0; x < allChatSearchResults.messages.length; x++){
var result = allChatSearchResults.messages[x];
result['type'] = 'message';
allResults[allResults.length] = result;
}
Is there a method i can use to loop through the array allResults and reorder this array to match the search query.
The array output is like this for a search of 'user':
allResults = [
{
type : 'user',
f_name : 'username',
l_name : 'somename'
},
{
type : 'message',
message : 'this is my user name', ////// query from sql matches this
date : '11/04/2016'
},
{
type : 'message',
message : 'another containing username', ////// query from sql matches this
date : '09/04/2016'
},
//and so on
];
Full Code:
var searchResultsSource = 0;
var allChatSearchResults = {users : [], messages : []};
var searchChatResults = function (type, query, res){
searchResultsSource++;
if(res.length > 0){
for(var x = 0; x < res.length; x++){ allChatSearchResults[type][x] = res[x]; }
}
if(searchResultsSource == 2){
//run the function
console.log('Search Results', allChatSearchResults);
var allResults = [];
// create an array of all
for(var x = 0; x < allChatSearchResults.users.length; x++){
var result = allChatSearchResults.users[x];
result['type'] = 'user';
allResults[allResults.length] = result;
}
for(var x = 0; x < allChatSearchResults.messages.length; x++){
var result = allChatSearchResults.messages[x];
result['type'] = 'message';
allResults[allResults.length] = result;
}
// create an array of just search query
// reorder the array based on the ordered search query
}
};
var searchChats = function () {
var query = $('#activeChatSearch').val();
query = query.toLowerCase();
if(query.length > 3){
//search my chats
//search users and search messages
db.transaction(function(tx) {
var users = [];
var chats = [];
var messages = [];
tx.executeSql("SELECT * FROM contacts WHERE f_name LIKE ? ORDER BY (CASE WHEN f_name = ? THEN 1 WHEN f_name LIKE ? THEN 2 ELSE 3 END), f_name ",["%" + query + "%", query, query + "%"], function (tx, res){
if(res.rows.length == 0){ console.log('no users with first name ' + query); }
for(var x = 0; x < res.rows.length; x++){ users[x] = res.rows.item(x); }
searchChatResults('users', query, users);
}, function (tx, error){
console.log(error.message);
});
tx.executeSql("SELECT * FROM active_chats ORDER BY last_changed DESC", [], function (tx, res){
if(res.rows.length > 0){
var count = 0;
var max = res.rows.length;
var results = res.rows;
var searchThisChat = function (tx, query, chatID){
tx.executeSql("SELECT * FROM chat_" + chatID + " WHERE message LIKE ? ORDER BY (CASE WHEN message = ? THEN 1 WHEN message LIKE ? THEN 2 ELSE 3 END), message LIMIT 0,1", ["%" + query + "%", query, query + "%"], function (tx, res){
if(res.rows.length == 0){ /*console.log('No chats match query',messages); */ }
else { messages[messages.length] = res.rows.item(0); }
if(count == max){ searchChatResults('messages', query, messages); } else{ searchThisChat(tx, query, results.item(count).chat_id); count++; }
}, function (tx, e){
console.log(e.message);
if(count == max){ searchChatResults('messages', query, messages); } else{ searchThisChat(tx, query, results.item(count).chat_id); count++; }
});
};
searchThisChat(tx, query, res.rows.item(0).chat_id);
}
}, function (tx, e){
console.log(e.message);
});
}, function(err) {
console.log('Open database ERROR: ', err);
});
var activeChats = $('#activeChats');
activeChats.html('');
for(var x = 0; x < 6; x++){
var item = formatCurrentChatItem(
{f_name : query, l_name : 'Bloggs', 'user_id' : 18},
null,
null
);
item.appendTo(activeChats);
}
}
};
$(function () {
$('#activeChatSearch').on('input', searchChats);
$('#activeChatSearchBtn').on('click', searchChats); <- input function
});
As you are not including the relevance score in the returned SQL, there is no way to combine two arrays.
First you need to return the score as part of your SQL:
tx.executeSql("SELECT *,(CASE WHEN f_name = ? THEN 1 WHEN f_name LIKE ? THEN 2 ELSE 3 END) as Score FROM contacts WHERE f_name LIKE ? ORDER BY (CASE WHEN f_name = ? THEN 1 WHEN f_name LIKE ? THEN 2 ELSE 3 END), f_name ",["%" + query + "%", query, query + "%"],onSuccess, onError);
Then you will be able to combine the arrays and sort by the 'Score' column:
allResults.sort(function(a,b){ return a.Score-b.Score; });