Looping through JSON using Node.js - sql

I am trying to loop through JSON using Node so that I can call a stored procedure in a sql database. the JSON is:
[ { boardid: '1', accesid: '2' },
{ boardid: '2', accesid: '3' },
{ boardid: '8', accesid: '4' } ]
the pseudo code i want to implement is: (I have the UserID)
var data = req.body.addJSON
for each JSON object {
con.query(
"CALL addUserToBoard('" + UserID + "', '" + BoardID + "','" + AccessTypeID + "');",
function(err, result, fields) {
if (err) throw err;
}
);
}

You can always interate in an Object a follows
var jsonresponse = JSON.parse(data);
Object.keys(jsonresponse).forEach( function(param , index) {
console.log(jsonresponse[param]);
console.log(index);
});

You could do this using a simple forEach,
var data = req.body.addJSON
data.forEach(value => {
con.query("CALL addUserToBoard('" + UserID + "', '" + value.boardid + "','" + value.accesid + "');", function (err, result, fields)
{
if (err) throw err;
});
})

Related

Cannot pass price into Stripe Checkout nodejs

I am using the embedded nodejs / javascript code for stripe checkout on my ecommerce website. However, I am trying to pass the name of the product(s) the customer will add to their cart, and the price as well, so I can display the items and prices on Stripe Checkout page.
I ran into the issue after making a connection to DB2, I cannot get the price of each item to be passed into the stripe checkout session. I think it may have to do with async, but even if it is, im not sure how to fix. I am also receiving the error: "(node:45673)UnhandledPromiseRejectionWarning: Error: Invalid integer: NaN"
(excuse the messy code. also some variables are not in use, just ignore)
app.post('/create-checkout-session', (req, res) => {
var amount = stringify(req.body)
console.log(req.body.sessionID)
var userId = req.body.sessionID
console.log("email: " + req.body.customer_email)
var email = req.body.customer_email;
var deliveryTotal = req.body.totalWithDelivery;
var totalVal = amount.split("=");
var totalPrice = parseFloat(totalVal[1]);
//console.log("TOTAL PRICE: " + totalPrice);
var finalPrice = parseFloat(Math.round(totalPrice * 100) / 100);
var finalTotal = parseFloat(Math.round(totalPrice * 100) / 100) + parseFloat(Math.round(deliveryTotal));
console.log("final total: " + finalTotal);
var itemName = ""
var itemPrice = ""
var totalNewPriceTest = ""
//query to database
var productsStripe = "select * from " + userId
console.log(userId)
console.log("query to db for displaying cart on stripe page")
ibmdb.open("DATABASE=BLUDB;HOSTNAME=;PORT=50000;PROTOCOL=TCPIP;UID="";PWD="";", function (err,conn) {
if (err) return console.log(err);
conn.query(productsStripe, function (err, rows) {
if (err) {
console.log(err)
}
console.log(rows)
for(var i = 0; i < rows.length; i++) {
itemName = rows[i]['ITEM']
itemPrice = rows[i]['PRICE']
totalNewPriceTest = parseFloat(rows[i]['PRICE'])
console.log("item name : " + itemName + " " + itemPrice )
totalNewPriceTest = parseFloat(totalNewPriceTest);
console.log("final overall prcie: " + (totalNewPriceTest))
}
console.log("inside productsStripe function.")
console.log("overall prcie: " + totalNewPriceTest)
})
})
totalNewPriceTest = parseFloat(totalNewPriceTest)
var grandTotal = totalNewPriceTest;
var finalGrandTotal = parseFloat(grandTotal)
console.log(parseFloat(finalGrandTotal))
//stripe
const session = stripe.checkout.sessions.create({
shipping_address_collection: {
allowed_countries: ['CA'],
},
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'CAD',
product_data: {
name: itemName,
},
unit_amount: finalGrandTotal,
//finalTotal * 100
},
quantity: 1,
},
],
mode: 'payment',
success_url: 'localhost:1001/successPg',
cancel_url: 'localhost:1001/catalogue',
customer_email: email,
});
console.log(session)
res.json({ id: session.id });
//console.log("customer id" + customer.id)
console.log("totalNewPriceTest " + totalNewPriceTest)
});
can anyone help? thank you in advance, and sorry for the terribly written code :(
You have to write following lines inside query callback :-
totalNewPriceTest = parseFloat(totalNewPriceTest)
var grandTotal = totalNewPriceTest;
var finalGrandTotal = parseFloat(grandTotal)
console.log(parseFloat(finalGrandTotal))
And for error check before parsing the data to int or float like
if(!isNAN(field))
value = parseFloat(field);
I did follow what you said, no errors, however it still doesn't reach the stripe checkout page... it logs in the console: Promise { }. i did research this and it says this has to once again do with async. not sure how to fix, read something about .then may work as well?
As you have guessed, it's a classic concurrency issue, first of all, this complete guide from MDN explains asynchronous javascript very well.
To briefly answer your case, you will need to continue executing stripe code in the query block. Why? Because you need to wait for the DB connection to open followed by a query execution, which both are asynchronous.
When you bypass those blocks, you're basically telling javascript to execute code in parallel, which in your case not what you want, you want to wait for the query to finish.
app.post('/create-checkout-session', (req, res) => {
var amount = stringify(req.body)
console.log(req.body.sessionID)
var userId = req.body.sessionID
console.log("email: " + req.body.customer_email)
var email = req.body.customer_email;
var deliveryTotal = req.body.totalWithDelivery;
var totalVal = amount.split("=");
var totalPrice = parseFloat(totalVal[1]);
//console.log("TOTAL PRICE: " + totalPrice);
var finalPrice = parseFloat(Math.round(totalPrice * 100) / 100);
var finalTotal = parseFloat(Math.round(totalPrice * 100) / 100) + parseFloat(Math.round(deliveryTotal));
console.log("final total: " + finalTotal);
var itemName = ""
var itemPrice = ""
var totalNewPriceTest = ""
//query to database
var productsStripe = "select * from " + userId
console.log(userId)
console.log("query to db for displaying cart on stripe page")
ibmdb.open("DATABASE=BLUDB;HOSTNAME=;PORT=50000;PROTOCOL=TCPIP;UID="";PWD="";", function (err,conn) {
if (err) return console.log(err);
conn.query(productsStripe, function (err, rows) {
if (err) {
console.log(err)
}
console.log(rows)
for(var i = 0; i < rows.length; i++) {
itemName = rows[i]['ITEM']
itemPrice = rows[i]['PRICE']
totalNewPriceTest = parseFloat(rows[i]['PRICE'])
console.log("item name : " + itemName + " " + itemPrice )
totalNewPriceTest = parseFloat(totalNewPriceTest);
console.log("final overall prcie: " + (totalNewPriceTest))
}
console.log("inside productsStripe function.")
console.log("overall prcie: " + totalNewPriceTest)
totalNewPriceTest = parseFloat(totalNewPriceTest)
var grandTotal = totalNewPriceTest;
var finalGrandTotal = parseFloat(grandTotal)
console.log(parseFloat(finalGrandTotal))
// continue executing here
//stripe
stripe.checkout.sessions.create({
shipping_address_collection: {
allowed_countries: ['CA'],
},
payment_method_types: ['card'],
line_items: [
{
price_data: {
currency: 'CAD',
product_data: {
name: itemName,
},
unit_amount: finalGrandTotal,
//finalTotal * 100
},
quantity: 1,
},
],
mode: 'payment',
success_url: 'localhost:1001/successPg',
cancel_url: 'localhost:1001/catalogue',
customer_email: email,
}).then((session) => {
console.log(session)
res.json({ id: session.id });
//console.log("customer id" + customer.id)
console.log("totalNewPriceTest " + totalNewPriceTest)
}).catch((err) => {
console.log('stripe err: ', err);
})
})
})
});
Other useful tips to follow:
Don't write business logic inside the router, instead create a controller file and move the logic into it.
Instead of connecting to the DB upon every request, create a DB connection instance and keep it open and available whenever you need it, start with creating its own helper file and then export the connection.

accessing route params an return as string

I'm looking to get route params from URL
created() {
this.token = this.getTokenParam();
console.log("Token " + this.token);
}
getTokenParam() : string {
const t = this.$route.params.token
console.log("Token " + this.$route.query.token);
if(t === null) return ''
else
return t;
}
Token
CfDJ8JrtUPxIgVlCopul3de0MqTwaW1Hukhm9RMfMIsi7kWP/6u89xVvJ4iAbcWTCTgrYvE9tcqZjYb3QvXrdhNEM2xLT0Ut8jdDDnfa0sKJFdXE8wYNZDwegDgEOkCBrPC6IZ
h5qcDTSb OaohaeEpk8RJXtp
sDD3sDTs/gY2xdB3oxQIfnqaTtBoEI/6C/QtyOGqPW7pWaikG1pRe4uM9j/KDo
OWMDwUoI tll4CeyM
Token undefined (why undefined??)
Are you reading it from query params?
const t = this.$route.query.token
console.log("Token " + this.$route.query.token);

How can I get cases another solution in IBM Case Manager?

I have two solutions.
How can I get cases another solution?
I think that icm.util.SearchPayload allows you to get the cases of the current solution.
buildPayload: function (values) {
if (!values) {
console.log("An invalid values is received!");
return;
}
var searchPayload = new icm.util.SearchPayload();
// CURRENT SOLUTION
var solution = this.widget.solution;
var params = {};
params.ObjectStore = solution.getTargetOS().id;
params.ceQuery = "SELECT t.[FolderName], t.[LastModifier], t.[DateLastModified], t.[CmAcmCaseTypeFolder], t.[CmAcmCaseState], t.[CmAcmCaseIdentifier], t.[DateCreated], t.[Creator], t.[Id], t.[ContainerType], t.[LockToken], t.[LockTimeout], t.[ClassDescription], t.[DateLastModified], t.[FolderName] FROM [CmAcmCaseFolder] t where ";
params.ceQuery += "t.[CmAcmCaseIdentifier] LIKE '%%' AND ";
for (var key in values) {
var attr = values[key].attr;
if (attr.dataType === "xs:string") {
params.ceQuery += "t.[" + key + "] LIKE '%" + values[key].value + "%' AND ";
} else {
params.ceQuery += "t.[" + key + "] = " + values[key].value + " AND ";
}
}
params.ceQuery = params.ceQuery.substring(0, params.ceQuery.length - 4);
var that = this;
this.widget.solution.retrieveCaseTypes(function (types) {
console.log(params.ceQuery);
params.caseType = types && types.length > 0 && types[0].name; // default to the first case type
params.solution = solution;
searchPayload.setModel(params);
var payload = searchPayload.getSearchPayload(function (payload) {
that.widget.onBroadcastEvent("icm.SearchCases", payload);
console.log(payload);
that.displayPayload(payload);
});
//
});
},
May be
ecm.model.desktop.retrieveSolutions?
Thank you!
Solution:
define(["dojo/_base/declare",
"dojo/_base/lang",
"dojo/_base/array",
"icm/base/Constants",
"icm/model/Case",
"ecm/LoggerMixin",
"icm/model/_DesktopMixin"],
function(declare, lang, array, Constants, Case, LoggerMixin, _DesktopMixin){
return declare("icm.custom.pgwidget.customSearchWidget.CustomWidgetContentPaneEventListener", [LoggerMixin, _DesktopMixin], {
searchTemplate: null,
widget: null,
constructor: function(widget){
this.widget = widget;
},
buildPayload: function(values) {
if(!values) {
console.log("An invalid values is received!");
return;
}
console.log("retrieveSolutions");
var that = this;
this.retrieveSolutions(function(solutionList) {
array.forEach(solutionList, function(solution) {
if (solution.id === "CBFPSFED_57_2") {
console.log("CBFPSFED_57_2");
var searchPayload = new icm.util.SearchPayload();
var params = {};
params.ObjectStore = solution.getTargetOS().id;
params.ceQuery = "SELECT t.[FolderName], t.[LastModifier], t.[DateLastModified], t.[CmAcmCaseTypeFolder], t.[CmAcmCaseState], t.[CmAcmCaseIdentifier], t.[DateCreated], t.[Creator], t.[Id], t.[ContainerType], t.[LockToken], t.[LockTimeout], t.[ClassDescription], t.[DateLastModified], t.[FolderName] FROM [CmAcmCaseFolder] t where ";
params.ceQuery += "t.[CmAcmCaseIdentifier] LIKE '%%' AND t.[JR572_name] LIKE '%%%'";
solution.retrieveCaseTypes(function(types) {
console.log(types);
console.log(params.ceQuery);
params.caseType = types && types.length > 0 && types[0].name; // default to the first case type
params.solution = solution;
searchPayload.setModel(params);
var payload = searchPayload.getSearchPayload(function(payload) {
that.widget.onBroadcastEvent("icm.SearchCases", payload);
console.log("buildPayload");
console.log(payload);
});
});
}
});
});
},
_eoc_: null
});
});
Key points:
icm/model/_DesktopMixin
this.retrieveSolutions(function(solutionList) {

node mssql binding in query

I'm new to SQL Server. When I was using MySQL, it was so easy to bind variables using '?'. However, I don't know how to bind variables in mssql.
I tried this:
const pool = new SQL.ConnectionPool(config, function (err) {
console.log('Connected to SQL server successfully');
});
var Myquery = "INSERT INTO person (idNumber, forename, surname, age, address, maritalStatus)" +
" VALUES( " + req.body.idNumber + ", " + req.body.forename + ", " + req.body.surname +
", " + req.body.age + ", " + req.body.address + ", " + req.body.maritalStatus + " )";
pool.request().query(Myquery, function (err, result) {
res.json(result);
})
I get this error:
Invalid column name 'single'.
However, when I execute the query I created here (Myquery) directly in SQL Server, it goes smoothly. How can I fix this?
edit:
const pool = new SQL.ConnectionPool(config, function (err) {
console.log('Connected to SQL server successfully');
});
const ps = new SQL.PreparedStatement(pool);
ps.input('param', SQL.NVarChar);
ps.prepare('SELECT * FROM #param', function (err) {
if (err) console.log('error: ' + err);
else {
ps.execute({param: 'person'}, function (err, result) {
console.log(result);
})
}
});
error: ConnectionError: Connection not yet open.
I used this too:
const pool = new SQL.ConnectionPool(config, function (err) {
console.log('Connected to SQL server successfully');
});
pool.request().input('param', SQL.NVarChar, 'person')
.query("SELECT * FROM #param", function (err, result) {
if (err) console.log('error: ' + err);
console.log(result);
});
error: ConnectionError: Connection is closed.
You need single quotes around your text values:
const pool = new SQL.ConnectionPool(config, function (err) {
console.log('Connected to SQL server successfully');
});
var Myquery = "INSERT INTO person (idNumber, forename, surname, age, address, maritalStatus)" +
" VALUES( " + req.body.idNumber + ", '" + req.body.forename + "', '" + req.body.surname +
"', " + req.body.age + ", '" + req.body.address + "', '" + req.body.maritalStatus + "' )";
pool.request().query(Myquery, function (err, result) {
res.json(result);
})
Also its a SUPER bad idea to create queries based on inputs this way as it allows SQL injection. You should use #parameters (https://blogs.msdn.microsoft.com/sqlphp/2008/09/30/how-and-why-to-use-parameterized-queries/)

SQL Error 42S22 when updating multiple records using query from server script in Azure Mobile Services

I'm currently running into problems while trying to customize the update script for a table of User Stories on Azure Mobile Services. My intention is to have the update script receive an item that contains an array of UserStory objects, construct a SQL string using that array, and then use mssql.query with that string against the UserStory table to update the individual records.
The following SQL achieves what I'm looking to do and works correctly when executed in Visual Studio:
UPDATE
masterstorylist.UserStory
SET
UserStory.relativepriority =
CASE UserStory.id
WHEN 'C36DC45B-170B-49F4-A747-6F4D989C1859' THEN '24'
WHEN '7EC413C3-17A8-410A-A394-ABF334364226' THEN '25'
WHEN '99890AFE-13C2-4E1A-8376-B501CB07080D' THEN '26'
END
Here's the server script that I have created in an attempt to achieve the same result:
function update(item, user, request) {
if(item.stories.length > 0){
var sql = "UPDATE masterstorylist.UserStory SET UserStory.relativepriority = CASE UserStory.id ";
for(var i = 0; i < item.stories.length; ++i){
sql+= ("WHEN '" + item.stories[i].id + "' THEN " + item.stories[i].relativepriority + " ");
}
sql+="END";
mssql.query(sql, {
success: function(results) {
request.respond();
},
error: function(err) {
request.respond(err);
}
});
}
else{
request.respond(statusCodes.NO_CONTENT, 'No records specified for update in request.');
}
}
The error I get back is
"sqlstate":"42S22","code:207"
which I think means that SQL can't find the relativepriority or id column. I've tried different syntax, such as qualifying the column names more or less or using [] around the columns, but the result is always the same.
I'm not sure what else to try, and details around creating and executing queries with the mssql object are hard to come by. I've been working off the examples here and here.
What am I missing?
EDIT: In case it helps, I reworked the code to see if using mssql.open would help. I modeled after the examples from the "MS Drivers for Node.js for SQL Server guide" (which I can't link to because I have low rep). The net result is the exact same error :/ Here's the new code in case it gives folks any ideas:
function update(item, user, request) {
if(item.stories.length > 0){
var sql = "UPDATE UserStory SET relativepriority = CASE id ";
for(var i = 0; i < item.stories.length; ++i){
sql+= ("WHEN '" + item.stories[i].id + "' THEN " + item.stories[i].relativepriority + " ");
}
sql+="END ";
console.log("opening connection...");
mssql.open({
success: function(connection){
console.log("mssql.open success");
console.log("executing query...");
connection.query(sql, function(err,results){
if(err){
console.log("query failed");
request.respond(err)
}
console.log("query successful");
request.respond();
});
},
error: function(err) {
console.log("fail on open: " + err);
request.respond(err);
}
});
}
else{
request.respond(statusCodes.OK, 'No records specified for update in request.');
}
}
P.S. This is my first post on Stack Overflow! :)
Ok, I figured out the answer to my own question. It turns out that the JSON object that the Mobile Service SDK was passing up wasn't formatted to the liking of Node.js. The item object coming into the script had an array of objects in it item.stories, which looked ok to me when it was logged to the console with console.log(item.stories); but apparently wasn't formatted well enough for me to access the individual objects in the 'item.stories' array using array notation.
I was able to fix both of the scripts above by adding the line var storiesToUpdate = JSON.parse(item.stories); and then using storiesToUpdate[i] instead of item.stories[i]. That seems to have done the trick. Ideally I'll find a way to fix the JSON generated on my clients so that I don't need this extra JSON.parse.
Here are three now working examples on how to update multiple records at once.
Simplest way to do what I wanted:
var storiesToUpdate;
var returnItem;
function update(item, user, request) {
storiesToUpdate = JSON.parse(item.stories);
returnItem = item;
if(storiesToUpdate.length > 0){
var sql = "UPDATE UserStory SET relativepriority = CASE id ";
for(var i = 0; i < storiesToUpdate.length; ++i){
sql+= ("WHEN '" + storiesToUpdate[i].id + "' THEN " + storiesToUpdate[i].relativepriority + " ");
}
sql+="END ";
mssql.query(sql,{
success: function(connection){
request.respond(statusCodes.OK, returnItem);
},
error: function(err) {
console.log("fail on open: " + err);
request.respond(err);
}
});
}
else{
request.respond(statusCodes.OK, returnItem);
}
}
Another way using mssql.open as well (not sure why you'd ever want to do this...):
var storiesToUpdate;
var returnItem;
function update(item, user, request) {
storiesToUpdate = JSON.parse(item.stories);
returnItem = item;
if(storiesToUpdate.length > 0){
var sql = "UPDATE UserStory SET relativepriority = CASE id ";
for(var i = 0; i < storiesToUpdate.length; ++i){
sql+= ("WHEN '" + storiesToUpdate[i].id + "' THEN " + storiesToUpdate[i].relativepriority + " ");
}
sql+="END ";
console.log("opening connection...");
mssql.open({
success: function(connection){
console.log("mssql.open success");
console.log("executing query...");
connection.query(sql, function(err,results){
if(err){
console.log("query failed");
request.respond(err)
}
console.log("query successful");
request.respond(statusCodes.OK, returnItem);
//request.respond(statusCodes.OK);
});
},
error: function(err) {
console.log("fail on open: " + err);
request.respond(err);
}
});
}
else{
request.respond(statusCodes.OK, returnItem);
}
}
And lastly, here's how to update multiple records without using mssql using the recommended batching techniques (this is rough and probably needs to be cleaned up):
var UserStoryTable = tables.getTable('UserStory');
var batchSize = 10;
var startIndex = 0;
var endIndex = 0;
var totalCount = 0;
var errorCount = 0;
var g_item;
var g_request;
var storiesToUpdate;
function update(item, user, request) {
//the json array has to be parsed first
storiesToUpdate = JSON.parse(item.stories);
g_item = item;
g_request = request;
if(item.stories.length > 0){
updateItems();
}
else{
console.log("empy update request");
request.respond(statusCodes.OK);
}
}
function updateItems(){
var batchCompletedCount = 0;
var updateComplete = function() {
batchCompletedCount++;
totalCount++;
if(batchCompletedCount === batchSize || totalCount === storiesToUpdate.length) {
if(totalCount < storiesToUpdate.length) {
// kick off the next batch
updateItems();
} else {
// or we are done, report the status of the job
// to the log and don't do any more processing
console.log("Update complete. %d Records processed. There were %d errors.", totalCount, errorCount);
g_request.respond(statusCodes.OK);
}
}
};
var errorHandler = function(err) {
errorCount++;
console.warn("Ignoring insert failure as part of batch.", err);
updateComplete();
};
var startIndex = totalCount;
var endIndex = totalCount + batchSize - 1;
if(endIndex >= storiesToUpdate.length) endIndex = storiesToUpdate.length - 1;
for(var i = startIndex; i <= endIndex; i++) {
console.log("Updating: " + storiesToUpdate[totalCount]);
UserStoryTable.update(storiesToUpdate[i],{
success: updateComplete,
error: errorHandler
});
}
}