I have an Nodejs express function where I am trying to insert data that is stored in the browser session into my postgres database. When I have the insert statement like this, the insert works but the session-stored customer_id isn't inserted and is just left null.
On the line with "var sql = INSERT INTO journal....", the values $1 and $2 are from user input and work correctly.
How can I get value 3 of the customer_id stored in the session to insert correctly? I would appreciate any advice or greater understanding.
app.post("/addJournalEntry", addJournalEntry);
function addJournalEntry(req, res) {
console.log("Posting data");
// var id = req.query.id;
//body is for post, query is for get
const customer_id = req.session.customer_id;
const journal_entry_date = req.body.journal_entry_date;
const journal_entry = req.body.journal_entry;
const params = [journal_entry, journal_entry_date, customer_id];
addEntryFromDataLayer(params, function (error, addEntry) {
console.log("Back From the addEntryFromDataLayer:", addEntry);
if (error || addEntry == null) {
res.status(500).json({
success: false,
data: error
});
}
else {
// res.json(result);
res.status(200).json(addEntry);
}
});
}
function addEntryFromDataLayer(params, callback) {
console.log("addEntryFromDataLayer called with id");
var sql = "INSERT INTO journal (journal_entry, journal_entry_date, customer_id) VALUES($1::text, $2::text, $3)";
// var params = [id];
pool.query(sql, params, function (err, addEntry) {
if (err) {
console.log("error in database connection");
console.log(err);
callback(err, null);
}
console.log("Found DB result:" + JSON.stringify(addEntry));
callback(null, addEntry);
});
}
Related
I'm using PostgreSQL with nodejs for the first time. I want to make several PostgreSQL queries atomic in case of error.
For example:
const group = Group.of(body);
const { rows } = await this.db.query(
`INSERT INTO groups
(\"defaultImage\", \"createdAt\", \"updatedAt\")
VALUES ($1, $2, $3)
RETURNING *`,
[group.defaultImage, group.createdAt, group.updatedAt]);
const groupId = rows[0].id;
group.images.map(image => {
return this.db.query(
`INSERT INTO groups_images
(\"groups_id\", \"uri\")
VALUES ($1, $2)`,
[groupId, image.uri]);
});
If the second query fails, I want the first to be rolled back
Using Transaction will solve the problem as explained here:
const { Pool } = require('pg')
const pool = new Pool()
;(async () => {
// note: we don't try/catch this because if connecting throws an exception
// we don't need to dispose of the client (it will be undefined)
const client = await pool.connect()
try {
await client.query('BEGIN')
const queryText = 'INSERT INTO users(name) VALUES($1) RETURNING id'
const res = await client.query(queryText, ['brianc'])
const insertPhotoText = 'INSERT INTO photos(user_id, photo_url) VALUES ($1, $2)'
const insertPhotoValues = [res.rows[0].id, 's3.bucket.foo']
await client.query(insertPhotoText, insertPhotoValues)
await client.query('COMMIT')
} catch (e) {
await client.query('ROLLBACK')
throw e
} finally {
client.release()
}
})().catch(e => console.error(e.stack))
https://node-postgres.com/features/transactions
Hello I'm trying to take data from a sql table but the data that I want to check is into an array, so I need compare the data to check if an user is into the group, the array only have the IDs from users and the specific ID that I want is being bringing to me through the login.
This code is in Typescript.
If you need more information let me know please.
class CompanyController {
async consultCompanys(req: Request, res: Response) {
let response: ResponseModel = new ResponseModel(ECodeResponse.Ok, "", []);
const { UserId } = req.body;
try {
const Companies: any = await pool.query(
`SELECT (CompanyId) From Companies Where Members = '${UserId}'`
);
response.Code = ECodeResponse.Ok;
response.Message = EWarningMessage.Error;
return res.json(response);
} catch (error) {
response.Code = ECodeResponse.Warning;
response.Message = EWarningMessage.Error;
return res.json(response);
}
}
}
I'm a litle oxidated in this kind of consults
I'm trying to dynamically make a patch request for oracle tables through Node.JS
Here's my setup:
In my router.js file I have this:
const express = require('express');
const router = new express.Router();
const employees = require('../controllers/employees.js');
const smiCats = require('../controllers/smi/smiCats.js');
const auth = require('../controllers/auth.js');
router.route('/login/:id?')
.post(auth.getToken);
router.route('/ams/:id?')
.get(auth.verifyToken, employees.get)
.post(auth.verifyToken, employees.post)
.put(auth.verifyToken, employees.put)
.delete(auth.verifyToken, employees.delete)
.patch(auth.verifyToken, employees.patch);
router.route('/smi/cats/:id?')
.get(auth.verifyToken, smiCats.get)
.post(auth.verifyToken, smiCats.post)
.put(auth.verifyToken, smiCats.put)
.patch(auth.verifyToken, smiCats.patch);
module.exports = router;
That then calls my controller that has my patch function & gets sanitized.
//sanitizer
function sanitizeCats(req) {
const cats = {
cat_desc: req.body.cat_desc,
msg_for: req.body.msg_for,
msg_user_owner: req.body.msg_user_owner || 0,
msg_realtor_owner: req.body.msg_realtor_owner || 0
};
return cats;
}
async function patch(req, res, next) {
try {
let category = sanitizeCats(req);
category.cat_id = parseInt(req.params.id, 10);
const success = await smiCats.patch(category);
if (success) {
res.status(204).end();
} else {
res.status(404).end();
}
} catch (err) {
next(err);
}
}
module.exports.patch = patch;
When that gets executed it calls my db_api module, which assembles the sql statement
(THE NEXT CODE SECTION IS WHERE MY QUESTION COMES FROM)
const database = require('../../services/database.js');
const oracledb = require('oracledb');
const patchSql =
`BEGIN
DECLARE
BEGIN
IF nvl(:cat_desc,'zzz') != 'zzz' THEN
UPDATE smi_contact_cats
SET cat_desc = :cat_desc
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_for,'zzz') != 'zzz' THEN
UPDATE smi_contact_cats
SET msg_for = :msg_for
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_user_owner,-1) > -1 THEN
UPDATE smi_contact_cats
SET msg_user_owner = :msg_user_owner
WHERE cat_id = :cat_id;
END IF;
IF nvl(:msg_realtor_owner,-1) > -1 THEN
UPDATE smi_contact_cats
SET msg_realtor_owner = :msg_realtor_owner
WHERE cat_id = :cat_id;
END IF;
:rowcount := sql%rowcount;
END;
END;`;
async function patch(cats) {
const category = Object.assign({}, cats);
//add binds
category.rowcount = {
dir: oracledb.BIND_OUT,
type: oracledb.NUMBER
};
const result = await database.simpleExecute(patchSql, category);
return result.outBinds.rowcount === 1;
}
module.exports.patch = patch;
This then calls the database function to actually execute & assemble the sql with the bind variables:
const oracledb = require('oracledb');
const dbConfig = require('../config/database.js');
async function initialize() {
const pool = await oracledb.createPool(dbConfig.beta);
}
module.exports.initialize = initialize;
async function close() {
await oracledb.getPool().close();
}
module.exports.close = close;
function simpleExecute(statement, binds = [], opts = {}) {
return new Promise(async (resolve, reject) => {
let conn;
opts.outFormat = oracledb.OBJECT;
opts.autoCommit = true;
try {
conn = await oracledb.getConnection();
const result = await conn.execute(statement, binds, opts);
resolve(result);
} catch (err) {
reject(err);
} finally {
if (conn) { // conn assignment worked, need to close
try {
await conn.close();
} catch (err) {
console.log(err);
}
}
}
});
}
module.exports.simpleExecute = simpleExecute;
So all of this works... but it's not dynamic enough for me to build our company api. How do I make a more dynamic patch request in Node.JS without having to type out every single column & put an nvl around it to check if it's there. As a side not if there's a better way to dynamically sanitize as well, I'm all ears, but the main question is on how to dynamically build the patch request better.
The current code is suboptimal in that is does one update per property. Here's a more dynamic solution...
Given the following:
create table smi_contact_cats (
cat_id number,
cat_desc varchar2(50),
msg_for varchar2(50),
msg_user_owner varchar2(50),
msg_realtor_owner varchar2(50)
);
insert into smi_contact_cats (
cat_id,
cat_desc,
msg_for,
msg_user_owner,
msg_realtor_owner
) values (
1,
'cat_desc orginal value',
'msg_for orginal value',
'msg_user_owner orginal value',
'msg_realtor_owner orginal value'
);
commit;
You can use logic like this. updatableColumns is the whitelist of columns that can be updated. Note that you can comment and uncomment some of the lines toward the bottom to test various input.
const oracledb = require('oracledb');
const config = require('./db-config.js');
async function patch(cat) {
let conn;
try {
const category = Object.assign({}, cat);
const categoryProps = Object.getOwnPropertyNames(category);
const updatableColumns = ['cat_desc', 'msg_for', 'msg_user_owner'];
// Validate that the pk was passed in
if (!categoryProps.includes('cat_id')) {
throw new Error('cat_id is required');
}
// Now remove the pk col from categoryProps
categoryProps.splice(categoryProps.indexOf('cat_id'), 1);
if (categoryProps.length === 0) {
throw new Error('At least one property must be specified');
}
let sql = 'update smi_contact_cats\nset ';
for (let propIdx = 0; propIdx < categoryProps.length; propIdx++) {
// Here's the whitelist check
if (!updatableColumns.includes(categoryProps[propIdx])) {
throw new Error('Invalid "update" column');
} else {
if (propIdx > 0 && propIdx < categoryProps.length) {
sql += ',\n ';
}
sql += categoryProps[propIdx] + ' = :' + categoryProps[propIdx];
}
}
sql += '\nwhere cat_id = :cat_id';
console.log('here is the sql', sql);
conn = await oracledb.getConnection(config);
const result = await conn.execute(
sql,
category,
{
autoCommit: true
}
);
if (result.rowsAffected && result.rowsAffected === 1) {
return category;
} else {
return null;
}
} catch (err) {
console.error(err);
} finally {
if (conn) {
try {
await conn.close();
} catch (err) {
console.error(err);
}
}
}
}
const patchObj = {
cat_id: 1
};
// Comment and uncomment the following to see various dynamic statements
patchObj.cat_desc = 'cat_desc value';
patchObj.msg_for = 'msg_for value';
patchObj.msg_user_owner = 'msg_user_owner value';
// Uncomment the following line to add a column that's not whitelisted
//patchObj.msg_realtor_owner = 'msg_realtor_owner value';
patch(patchObj)
.then(function(cat) {
console.log('Updated succeeded', cat);
})
.catch(function(err) {
console.log(err);
});
I am trying to right a function that copies some fields from several company databases into my own database once a day. What I have so far is below. I am wondering if where I console.log(rs) I can open another sql connection to my database and write the data or if I have to store the results somewhere and then open a new connection and send the stored results.
function updateJobs() {
var query = "SELECT JobStart, JobEnd FROM JobData";
sql.connect(Config, (err) => {
if (err) {
console.log("Error while connecting database :- " + err);
} else {
var request = new sql.Request();
request.query(query, function (err, rs) {
if (err) {
console.log("Error while querying database :- " + err);
sql.close();
} else {
console.log(rs);
sql.close();
}
})
}
})
}
This might help
// Source Database
sourceDB.each(`select * from ${Sourcetable}`, (error, row) => {
console.log(row);
const keys = Object.keys(row); // ['columnA', 'columnB']
const columns = keys.toString(); // 'columnA,columnB'
let parameters = {};
let values = '';
// Generate values and named parameters
Object.keys(row).forEach((r) => {
var key = '$' + r;
// Generates '$columnA,$columnB'
values = values.concat(',', key);
// Generates { $columnA: 'ABC', $columnB: 'GHK' }
parameters[key] = row[r];
});
// Insert into another database into OneTable (columnA,columnB) values ($columnA,$columnB)
// Parameters: { $columnA: 'ABC', $columnB: 'GHK' }
destDB.run(`insert into ${Desttable} (${columns}) values (${values})`, parameters);
})
})
I'm running this SQL query with tedious.js using parameters:
var query = "select * from table_name where id in (#ids)";
request = new sql.Request(query, function(err, rowCount) {
if (err) {
}
});
request.on('row', function(columns) {
});
var id = [1, 2, 3];
request.addParameters('ids', TYPES.Int, id);
connection.execSql(request);
because I am looking for items that matches the ID provided with where ... in ... clause, I need to pass in an array. However, there is no TYPES.Array. How do I this properly?
for this query, i think you'll just have to manually build the entire sql string. the TYPES enum values are for the datatypes in the database, not in your JavaScript code.
//you can like this:
var userIds = result.map(function (el) {
return el.UserId;
}).join(',');
var params = [{
name: 'userIds',
type: TYPES.VarChar,
value: userIds,
options: null}];
var querySql = ['SELECT COUNT([MomentId]) FROM [T_Moment]',
'WHERE [RecordStatus] = ', sysConst.recordStatus.activation, " AND CHARINDEX(','+RTRIM([UserId])+',' , ','+ #userIds +',')>0 "].join(' ');
dbHelper.count(querySql, params, function (err, result) {
if (err) {
callback('error--');
} else {
callback(null, result);
}
});
Try creating the in clause parameters for query dynamically.
// create connection
let ids = [1, 2, 3];
let inClauseParamters = createInClauseParameters();
let query = `select * from table_name where id in (${inClauseParamters})`;
let request = new Request(query, (err, rowCount) => {
if (err) { /* handle error */ }
});
request.on('row', (columns) => { /* get row */});
request = addRequestParameters(ids, request);
connection.execSql(request);
function createInClauseParameters(values) {
return values.map((val, index) => `#Value${index}`).join(',');
}
function addRequestParameters(values, request) {
values.forEach((val, index) => {
request.addParameter(`Value${index}`, TYPES.VarChar, val);
});
return request;
}