I am working on a React project with PostgreSQL database, this is the first time I am using it, and I am getting 42703 error on querying a particular column.
Below is the code I have written to query
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id=${userId}`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
I have defined this getList function and then I am making an api call to call this function by passing the userId like this
app.get(`/expenses`, verifySession(), async (req, res) => {
const userId = req.session.userId;
database.getList(userId)
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
I even tried passing the userId directly as shown below , still it gives me the same error , which probably means I am querying in a wrong way
app.get(`/expenses`, verifySession(), async (req, res) => {
//const userId = req.session.userId;
database.getList('17a6dea6-a63e-4da7-9910-df7eddb672e6')
.then(response => {
res.status(200).send(response);
})
.catch(error => {
res.status(500).send(error);
})
})
Only when I directly write the string in the query it works properly like this
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id='17a6dea6-a63e-4da7-9910-df7eddb672e6'`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
Can someone please help we with what is exactly going wrong and if my syntax is correct or not ?
This is the frontend part of where I am calling the api.
function getDataForUser() {
fetch(`http://localhost:3001/data`)
.then(response => {
return response.json();
}).then(data => {
console.log(data.rows[0]);
})
}
This problem happened because you didn't use a single quotation for string type in the query. When using where id=${userId} and called with 17a6dea6-a63e-4da7-9910-df7eddb672e6 converted to where id=17a6dea6-a63e-4da7-9910-df7eddb672e6 and this make problem.
You can use two scenarios to handle it:
Use the single quotation for string type:
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id='${userId}'`, (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
Use parameter binding (As default it converted type)
const getList = (userId) => {
return new Promise(function (resolve, reject) {
pool.query(`SELECT items FROM public."user" where id=$1`, [userId], (error, results) => {
if (error) {
reject(error)
}
resolve(results);
})
})
}
Related
I am fetching cricket matches and scores from different http requests. The first one fetch match list(with unique ids) and second one fetch scores using unique id. I need the second http request(data.map function) to be completed, then data variable value to be sent(in res.json without using timeout). I know using Promises/Callbacks, but I am confused with code. Currently using setTimeout to wait, but I dont want to use timeout. Please Help.
app.get('/api/matches', (req, res) => {
let url = `http://cricapi.com/api/matches?apikey=${key}`
request(url, { json: true }, (err, resp, body) => {
if (err) return res.json({
error: 1,
msg: err,
})
let data = body.matches.filter(match => {
return match.matchStarted
})
data.map((element, index) => {
let requrl = `http://cricapi.com/api/cricketScore?apikey=${key}&unique_id=${element.unique_id}`
request(requrl, { json: true }, (err, resp, body) => {
element.score = body.score
data.push(element)
})
})
setTimeout(()=>{
res.json({
error: 0,
matches: data
})
},2000)
})
})
Expecting output to be cricket matches with their score, but without timeout function, current output is undefined.
Try wrapping map inside promise like this.
app.get('/api/matches', (req, res) => {
let url = `http://cricapi.com/api/matches?apikey=${key}`
request(url, { json: true }, (err, resp, body) => {
if (err) return res.json({
error: 1,
msg: err,
})
let data = body.matches.filter(match => {
return match.matchStarted
})
let newData = data.map((element, index) => {
return new Promise((resolve, reject) => {
let requrl = `http://cricapi.com/api/cricketScore?apikey=${key}&unique_id=${element.unique_id}`
request(requrl, { json: true }, (err, resp, body) => {
element.score = body.score
resolve(element);
})
});
})
Promise.all(newData).then(data => {
res.json({
error: 0,
matches: data
})
})
})
})
You should use async/await to wait your requests to finish, so what you can do is, so you need to use request-promise package which supports promises, so you can use async await, see at their documentation here
npm install request-promise
Implement async/await as below
const request = require('request-promise');
app.get('/api/matches', async (req, res) => {
let url = `http://cricapi.com/api/matches?apikey=${key}`
let { response, body } = await request({ uri: url, method: 'GET' })
if (response.statusCode !== 200){
return res.json({ error: 1, msg: err,})
}
let data = body.matches.filter(match => {
return match.matchStarted
})
await Promise.all(data.map(async (element, index) => {
let { response, body } = await request({ uri: url, method: 'GET' })
element.score = body.score
data.push(element)
}))
return res.json({ error: 0, matches: data })
}
Wrap every request in a Promise and chain them.
Psuedo code:
// Promise for match
const getMatch = new Promise((resolve, reject) => {
// Do request, call resolve (or reject) when completed.
request(url, resolve);
});
// Promise for score
const getScore(id) = new Promise((resolve, reject) => {
// Do request, call resolve (or reject) when completed.
request(url, resolve);
});
// Chain promises
getMatch()
.then(match => getScore(match))
.then(profit => console.log(profit)
.catch(error => console.warn(error)
I am trying to refactor this code using try-catch blocks:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
}).catch(error => console.log(error));
}
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
}).catch(error => console.log(error));
}
However I'm not getting the same result - the asynchronousity seems to be being handled differently. Here is my attempt at refactoring:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
try {
ConnectyCube.login(userCredentials, (error, user) => {
return user;
})
}
catch (error) {
console.log(error)
}
}
const createSession = () => {
try {
ConnectyCube.createSession((error, session) => {
return session.user
})
} catch (error) {
console.log(error);
}
}
Is there any particular part of what I'm wrong? Thanks.
Callback-based APIs don't readily turn into something you can use for async/await (which under the hood uses promises). You'll have to "promisify" them first (i.e. wrap them in promises).
Here's an example of what I'm trying to say:
// Promisify these callback-based APIs.
const login = userCredentials => {
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
})
})
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
})
})
// Then use them in an async function
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
}
try {
await createSession()
return login(userCredentials)
} catch (e) {
console.warn(e)
}
}
Also, async functions return promises, with the resolved value being the return value, and the rejected value being any uncaught error thrown inside. A value wrapped in a promise as return value for an async function is redundant.
If you're using Node 8+, it has a utility called promisify which accepts a callback-based API and returns a promise-returning version of it.
I have a route like:
router.get("/my_resource", myController.getResult);
Then my controller is like:
getResult: async (req, res, next) => {
try {
const param = req.query.param;
let response = {};
if (param) {
let [result1, result2] = await Promise.all([myModel.getResult1(param), myModel.getResult2(param)]);
console.log(result1);
console.log(result2);
}
res.send(response);
} catch (e) {
next(e);
}
}
And my model (which is querying a mongodb) looks like:
getResult1: (param) => {
new Promise((resolve, reject) => {
MongoSchema1.findById(param, (error, result) => {
if (error) return reject(error);
resolve(result ? result : {});
}).select("field1 field2");
})
}
getResult2: (param) => {
new Promise((resolve, reject) => {
MongoSchema2.findById(param, (error, result) => {
if (error) return reject(error);
resolve(result ? result : {});
}).select("field1 field2");
})
}
Here, when I try to console.log() in the model functions I can see that the result is not undefined. I get the correct result. However, I can see that the console.log() in the controller method gets executed before the console.log() in the model methods.
In the code above, I'm making the async calls in parallel with Promise.all(). However, even if I try to run one at a time, I still get my result to be undefined in the controller method. What am I doing wrong? Do I need import any module before I can await? Thanks.
The problem is that your methods getResult1 and getResult2 do not return Promises objects.
Replace
getResult1: (param) => {
new Promise((resolve, reject) => {
MongoSchema1.findById(param, (error, result) => {
if (error) return reject(error);
resolve(result ? result : {});
}).select("field1 field2");
})
}
By
getResult1: (param) => {
return new Promise((resolve, reject) => {
MongoSchema1.findById(param, (error, result) => {
if (error) return reject(error);
resolve(result ? result : {});
}).select("field1 field2");
});
}
Or
getResult1: param => new Promise((resolve, reject) => {
MongoSchema1.findById(param, (error, result) => {
if (error) return reject(error);
resolve(result ? result : {});
}).select("field1 field2"));
}
Or
getResult1: async param => (await MongoSchema1.findById(param).select('field1 field2')) || {};
Or
getResult1: async param => (await MongoSchema1.findById(param, 'field1 field2')) || {};
My problem is that i coded a simple overstock function for my game-items trading site (site working with socket.io!). And when the site is loading, two functions getting user and site inventories with items and listing them into two boxes, but the user inv loads faster and info about overstock comes later as the bot inv is loaded. I need to execute the "get user inventory" function after the "get bot inventory" function is fully done. I tried to set a sleep function between them, but it worked only for the main function that loading whole functions. In other words sleep(2000) delays loading both inventories when it set between this two functions.
sorry for my bad english :-D
Aaand there is my code (i left only important part):
io.on('connection', (socket) => {
var userObject = false
if (
typeof socket.handshake.session.passport !== 'undefined' &&
typeof socket.handshake.session.passport.user !== 'undefined' &&
typeof socket.handshake.session.passport.user.id !== 'undefined'
) {
userObject = socket.handshake.session.passport.user
}
socket.emit('site', config.site)
socket.emit('user', userObject)
socket.on('get bot inv', (id) => {
Trade.getInventory(config.bots[id].steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('bot inv', { error: err, items: data })
})
})
socket.on('get user inv', (steamID64) => {
Trade.getInventory(steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('user inv', { error: err, items: data })
})
})
socket.on('get bots inv', () => {
const params = []
Object.keys(config.bots).forEach((index) => {
const bot = config.bots[index]
params.push({
id: index,
steamID64: bot.steamID64,
appID: config.appID,
contextID: config.contextID,
})
})
Trade.getInventories(params, (data) => {
socket.emit('bots inv', data)
socket.emit('bots floats', Trade.getFloatValues())
})
})
})
Look into promises.
var promise1 = new Promsie((resolve, reject) => {
socket.on('get bot inv', (id) => {
Trade.getInventory(config.bots[id].steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('bot inv', { error: err, items: data })
resolve();
})
})
})
var promise2 = new Promsie((resolve, reject) => {
socket.on('get user inv', (steamID64) => {
Trade.getInventory(steamID64, config.appID, config.contextID, (err, data) => {
socket.emit('user inv', { error: err, items: data })
resolve();
})
})
})
If you want to wait until one finishes
promise1.then(() => {return promise2});
If you want N things to execute and await all of them, use the following
Promise.all([promise1, promise2]).then(() => {execute something else});
For further documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
You might want to use promises. At first, encapsulate the socket listeners and the API call with promises:
const getUserId = new Promise(res => socket.on('get bot inv', res));
const getBotId = new Promise(res => socket.on('get bot inv', res));
function getInventory(id) {
return new Promise((res, rej) => {
Trade.getInventory(id, config.appID, config.contextID, (err, data) => {
if(err) rej(err) else res(data);
});
}
Then its easy to chain the promises:
(async function() {
const userID = await getUserId;
const data = await getInventory(userID);
socket.emit({ data });
const botID = await getBotId;
const botData = await getInventory(config.bots[botID].steamID64);
socket.emit({ botData });
})();
So I am running a few insert queries using the mysql npm package and I'm doing so with Promise.all to try and run them at the same time. I have a function that creates a new connection for each query and returns a promise. I am also wrapping the mysql queries with promises. Here is the code that builds the queries and calls them with Promise.all
const Database = require('./database');
const queryBuilder = record =>
new Promise((resolve, reject) => {
try {
const filename = record.s3.object.key.split('/').pop();
const filesize = record.s3.object.size;
const s3path = `${record.s3.bucket.name}/${record.s3.object.key}`;
const createdAt = record.eventTime.split('T').shift();
const sql = 'INSERT INTO raw_files (filename, filesize, s3path, created_at, client_subdomain) ' +
`VALUES ('${filename}', ${filesize}, '${s3path}', '${createdAt}', '${record.s3.bucket.name}')`;
resolve(sql);
} catch (err) {
reject(err);
}
});
const connectionWrapper = (params, record) =>
new Promise((resolve, reject) => {
const db = new Database(params);
db.connect()
.then(res => queryBuilder(record))
.then(sql => db.query(sql))
.then((res) => {
db.close();
resolve(res);
})
.catch((err) => {
db.close();
reject(err);
});
});
exports.handler = (event, context, callback) => {
const connectionParams = {
host: '127.0.0.1',
port: 3306,
user: 'root',
password: 'some_password',
database: 'space_util',
};
Promise.all(event.Records.map(record => connectionWrapper(connectionParams, record)))
.then(res => callback(null, res))
.catch(err => callback(err));
};
And then here is the wrapper module
const mysql = require('mysql');
// Promise-ify the mysql connection
const Database = function Database(connectionParams) {
this.connection = mysql.createConnection(connectionParams);
};
Database.prototype.connect = function connect() {
return new Promise((resolve, reject) => {
this.connection.connect((err) => {
if (err) reject(err);
resolve();
});
});
};
Database.prototype.query = function query(sql) {
return new Promise((resolve, reject) => {
this.connection.query(sql, (err, results, field) => {
if (err) reject(err);
resolve(results);
});
});
};
Database.prototype.close = function close() {
return new Promise((resolve, reject) => {
this.connection.close((err) => {
if (err) reject(err);
resolve('Connection closed');
});
});
};
module.exports = Database;
It works, but I am curious if the way I am doing this seems like a hack or not? Specifically the way I am calling the Promise.all with a map function as the argument. I didn't know how to make an array of connectionWrappers with their params without invoking them, hence the map function in Promise.all(). Any advice would be appreciated!