I tried to connect my Dialogflow agent with MySQL DB at my GCP, but it didn't work well.
I just wanna see the results in console, but there's no results about that.
I can only see the result "Undefined", but since I am not familiar with Node.js, I am not sure what this means.
Since there is no content in the result, I cannot proceed to the next step.
Here is my index.js script :
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const mysql = require('mysql');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function connectToDatabase() {
const connection = mysql.createConnection({
host: '34.64.***.***',
user: 'username',
password: 'password',
database: 'dbname'
});
return new Promise((resolve,reject) => {
connection.connect();
console.log('connection successed.');
resolve(connection);
});
}
function queryDatabase(connection, name){
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM tb_user WHERE name = ?', name, (error, results, fields) => {
console.log('query successed.');
resolve(results);
});
});
}
function queryDatabase2(connection){
return new Promise((resolve, reject) => {
connection.query('SELECT * FROM tb_user', (error, results, fields) => {
if (error) console.log(error);
console.log('results', results);
});
});
}
function handleReadFromMysql(agent) {
const user_name = agent.parameters.name;
console.log(user_name.name);
return connectToDatabase()
.then(connection => {
console.log('connectToDatabase passed');
return queryDatabase(connection, user_name.name)
//return queryDatabase2(connection)
.then(result => {
console.log('queryDatabase passed');
console.log(result);
agent.add(`User name is ${user_name} .`);
//result.map(user => {
//if(user_name === user.name) {
//agent.add(`UserID is ${user.id}`);
//}
//});
connection.end();
});
});
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('findName', handleReadFromMysql);
agent.handleRequest(intentMap);
});
and the logs are :
enter image description here
Please somebody help me...
I solved this problem 4 months ago, so I share my code to help another like me.
I use socketPath of DB info. I forgot the reason.
function connectToDatabase() {
const connection = mysql.createConnection({
socketPath: '/cloudsql/*************:asia-northeast3:****',
user: '****',
password: '****',
database: '****'
});
return new Promise((resolve, reject) => {
connection.connect();
console.log('connection successed.');
resolve(connection);
});
}
And make query function like :
function findNameCountQuery(connection, name) {
return new Promise((resolve, reject) => {
var sql = `SELECT * FROM tb_user WHERE name = ?`;
var execSql = connection.query(sql, [name], (error, results) => {
if (error) throw error;
resolve(results);
});
});
Then I use agent function like :
async function findName(agent) {
const user_name = agent.parameters.person.name;
const connection = await connectToDatabase();
const result = await findNameQuery(connection, user_name);
result.map(user => {
message += `사용자 ID seq number : ${user.seq}\n`;
});
agent.add(message);
connection.end();
}
Hope to be helpful.
Related
I am working on Password reset functionality in NodeJS and am facing Promise.resovle undefined issue. I am getting the corrrect values from the database and able to send the actual email, but the promise in the main function doesn't return anything.
Any help would be welcome.
Here is my main route function-
router.post('/reset-password', async (req, res) => {
const { email } = req.body
const emailCheck = await db.query('SELECT EXISTS (SELECT email from tickets where email=$1)', [email])
const ifExist = Object.values(emailCheck.rows[0])[0]
if (ifExist) {
const resetPin = Math.floor(100000 + Math.random() * 900000) //random 6 digit pin with 0 not as first digit
await db.query('UPDATE tickets SET pin=$1 where email=$2', [resetPin, email])
const result = await emailProcessor(email, resetPin)
console.log(result) /////returns undefined!
if (result) {
return res.status(401).json({
status: 'success',
message: 'Pin sent to email if present in our database'
})
}
}
res.status(403).json({
status: 'error',
message: 'Pin sent to email if present in our database'
})
Here is my helper function using nodemailer-
const transporter = nodemailer.createTransport({
host: 'randomhost',
port: 587,
auth: {
user: 'abc.email',
pass: '123'
}})
const sendEmail = (info) => {
return new Promise(async (resolve, reject) => {
try {
let result = await transporter.sendMail(info);
console.log("Message sent: %s", result.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(result));
resolve(result)
} catch (error) {
console.log(error)
}
})}
const emailProcessor = (email, pin) => {
const info = {
from: '"app" <email>',
to: email,
subject: "Reset Pin",
text: "Pin is " + pin,
html: `<b>Reset Pin</b><b>${pin}`,
}
sendEmail(info)}
emailProcessor doesn't currently have a return statement, so it implicitly returns undefined. Change it to:
const emailProcessor = (email, pin) => {
const info = {
from: '"app" <email>',
to: email,
subject: "Reset Pin",
text: "Pin is " + pin,
html: `<b>Reset Pin</b><b>${pin}`,
};
return sendEmail(info); // <------ added return
};
P.S, sendEmail does not need to use the promise constructor, new Promise. You're already using promises, so you just need to use the ones that are there, not make a new one.
const sendEmail = async (info) => {
try {
let result = await transporter.sendMail(info);
console.log("Message sent: %s", result.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(result));
return result;
} catch (error) {
console.log(error);
}
};
I want to export some functions from my database.js file and require them into the other file login.js, which is in the same folder. I tried also to declare the require globally and in a function, both ways did not work. I am using node.js/express.js.
DATABASE.JS
let mysql = require('mysql');
const connection = mysql.createConnection({
host: 'localhost',
database: 'minigames',
user: 'root',
password: 'root'
});
function connected(){
connection.connect((err) => {
if(err) throw err;
console.log("Connected...");
})
}
function select(attribute){
return new Promise((resolve, reject) => {
let sql = `SELECT ${attribute} FROM player`;
connection.query(sql, (err, result, field) => {
if(err) reject(err);
resolve(Object.values(JSON.parse(JSON.stringify(result))));
})
})
}
async function query(attribute) {
return await select(attribute);
}
module.exports = {connection, connected, select, query};
LOGIN.JS
let userList = [];
function checkLogin(){
const database = require('./database');
let userListPromise = database.query('username, password');
userListPromise
.then()
.then((values) =>{
let i = 0;
while(values[i] != null){
userList.push(values[i]);
i++;
}
console.log("list filled");
console.log(userList);
})
}
checkLogin();
This question already has answers here:
How to export asynchronously loaded data to be used in a different node module?
(1 answer)
How not to forget using await everywhere in Javascript?
(1 answer)
How can I export promise result?
(4 answers)
Closed last year.
I have the code below. I need to use the value of con in other functions but I have no possible solution for this. I tried using .thens and awaits like other stack articles but i kept getting the error that con is not valid.
I am truly stuck and unsure how to handle this.
service.js
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
}
}
// Start an IIFE to use `await` at the top level
(async function(){
let con = await connectToDatabase(secretName);
})();
function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
}
controller.js
async function getUsers(req, res, next) {
service.getUsers().then(function(val) {
res.json(val)
});
}
getsecretpromise
function getSecretPromise(secretName) {
return new Promise((resolve, reject) => {
client.getSecretValue({SecretId: secretName}, function(err, data)
{
//do stuff
}
}
service.getUsers
//this is in service.js
module.exports = {
createUser,
getUsers,
patchUser,
loginUser,
updateCallForward,
getEmail,
getCallForwardingNumber,
getDB
};
function getUsers() {
return new Promise((resolve, reject) => {
var sql = `sql`;
getDB().then(con => {
con.query(sql, function (err, result) {
if (err) throw err;
resolve(result);
});
});
});
}
You are defining the con variable after it's being returned, your IIFE starts working once it is read. What I am trying to say is you need to move that function up and if thats not an option then you need to define con before returning it. If you alredy defined it before this function then I dont know.
async function connectToDatabase(secret) {
// Start an IIFE to use `await` at the top level
(async function(){
let con = await connectToDatabase(secretName);
})();
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
}
}
function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
}
You would ideally do something like this. This would hide your instance(not really for this case) from rest of the code as you will access it through a getter function. Of course you need to import your secret as a constant. It doesn't make sense to pass it as a parameter unless you have multiple dbs
let con = null;
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
con.connect(function (err) {
if (err) throw err;
console.log("Connected to database!");
});
return con;
} catch (error) {
console.error(error)
con = null;
}
}
export async function getDB() {
if (con == null) {
let secretObj = {};
return await connectToDatabase(secretObj);
}
else {
return Promise.resolve(con);
}
}
export function createUser({ data }) {
return new Promise((resolve, reject) => {
var sql = `query`;
getDB().then(con => {
con.query(sql, function (err, result) {
//does not work currently because ReferenceError: con is not defined
});
});
});
}
The code can be simplified (and repaired) by making promise-returning versions of the mysql callback style functions...
async function connect(connection) {
return new Promise((resolve, reject) => {
connection.connect(function (err) {
err ? reject(err) : resolve(connection)
});
})
}
async function query(connection, query) {
return new Promise((resolve, reject) => {
connection.query(query, function (err, results, fields) {
err ? reject(err) : resolve({results, fields});
});
});
}
Only these functions should create new promises explicitly. This cleans up the connectToDatabase function...
async function connectToDatabase(secret) {
try {
const secretValue = await getSecretPromise(secret)
const { host, port, username, password, dbname } = JSON.parse(secretValue);
let con = mysql.createConnection({
host: host,
port: port,
user: username,
password: password,
database: dbname
});
return await connect(con);
} catch (error) {
console.error(error)
}
}
And it cleans up createUser substantially...
async function createUser({ data }) {
try {
const connection = await connectToDatabase(secretName);
let {results, fields} = query(connection, 'query');
// and so on
} catch(error) {
console.log(error);
}
}
Not that getSecretPromise() might require the same treatment, but is not completely specified in the OP.
Other caveats: not tested (or even compiled). Relies on values in scope whose definitions are not shown in the OP (e.g. secretName).
I have a nodejs project with the current structure below, I need to insert a registry on clients table and return the last inserted ID from this table so I can use it in a second table, but I need to wait until the insert is completed in clients table, before insert the client ID on my second table. I'm trying to use async/await, but I'm always getting a null value.
My MYSQL connection: db.model.js
const config = require('config');
const mysql = require("mysql");
const connection = mysql.createConnection({
host: config.get('mysql.host'),
user: config.get('mysql.user'),
password: config.get('mysql.password'),
database: config.get('mysql.database')
});
connection.connect(function (err) {
if (err) {
console.error(`MySQL Connection Error: ${err.stack}`);
return;
}
console.log(`MySQL connected successfully!`);
});
module.exports = connection;
My CLIENT model
const mysql = require("./db.model");
const Client = function(client) {
this.login = client.login;
};
Client.create = (newClient, result) => {
mysql.query("INSERT INTO clients SET ?", newClient,
(err, res) => {
if (err) {
console.log("error: ", err);
result(err, null);
return;
}
result(null, {
id: res.insertId,
...newClient
});
}
);
};
module.exports = Client;
this is the client controller (i'm trying to use async/await here)
const Client = require('../models/client.model');
exports.create = (login) => {
const client = new Client({
login: login
});
Client.create(client, async (err, data) => {
if(!err) {
return await data.id;
} else {
return false;
}
});
}
And this is another controller, where I want to use methods from my client controller:
const ClientController = require('../controllers/client.controller');
...
utils.connect()
.then(clt => clt.sub.create(data))
.then((sub) => {
let lastInsertedId = ClientController.create(sub.login);
// lastInsertedId always return null here,
// but I know ClientController return a value after some time.
// method below will fail because lastInsertedId cannot be null
TransactionController.transactionCreate(lastInsertedId,
sub.id,
sub.param);
})
.catch(error => res.send(error.response.errors))
any help appreciated.
File to create database connection
const config = require('config');
const mysql = require('mysql2');
const bluebird = require('bluebird');
const dbConf = {
host: config.dbhost,
user: config.dbuser,
password: config.dbpassword,
database: config.database,
Promise: bluebird
};
class Database {
static async getDBConnection() {
try {
if (!this.db) {
// to test if credentials are correct
await mysql.createConnection(dbConf);
const pool = mysql.createPool(dbConf);
// now get a Promise wrapped instance of that pool
const promisePool = pool.promise();
this.db = promisePool;
}
return this.db;
} catch (err) {
console.log('Error in database connection');
console.log(err.errro || err);
}
}
}
module.exports = Database;
Use connection to execute your native query
const database = require('./database');
let query = 'select * from users';
let conn = await dl.getDBConnection();
let [data, fields] = await conn.query(query);
So I'm still using only the npm mysql package, but now I transformed all my queries into promises like below, so I can just wait until all the queries are completed.
const create = (idCliente, transactionId, amount, status) => {
const sql = "INSERT INTO transactions SET ?";
const params = {
id_cliente: idCliente,
transaction_id: transactionId,
amount: amount,
status: status
};
return new Promise((resolve, reject) => {
pool.query(sql, params, (err, result) => {
if (err) {
return reject(err);
}
resolve(result);
});
});
};
then I use like this:
create(params)
.then((result) => {
//call more queries here if needed
})
.catch((err) => { });
You can use sync-sql package of npm for execute async queries.
https://www.npmjs.com/package/sync-sql
Here is an example of it:
const express = require('express')
const mysql = require('mysql')
const app = express()
var syncSql = require('sync-sql');
// Create Connection
const connect = {
host: 'localhost',
user: 'root',
password: '',
database: 'ddd_test'
}
const db = mysql.createConnection(connect)
db.connect((err) => {
if (err) {
throw err
}
console.log("Connected");
})
function getDbData(query) {
return syncSql.mysql(connect, query).data.rows
}
app.get("/getData", async (req, res, next) => {
let sql = 'SELECT * from registration';
res.json({
data:getDbData(sql)
});
})
app.listen(3000, () => {
console.log('App listening on port 3000!');
});
My problem is, I want to make INSERT query for every object from JSON using some loop, but I almost always got an error "Cannot set headers after they are sent to the client".Can someone help?Tnx
const connection = require('./config');
module.exports.excel = function (req, res) {
var _query = 'INSERT INTO excel (id, first_name, last_name) values ?';
var jsonData = req.body;
var values = [];
function database() {
return new Promise((resolve, reject) => {
jsonData.forEach((value) => {
values.push([value.id, value.first_name, value.last_name]);
connection.query(_query, [values], (error, results) => {
if (error) {
reject(
res.json({
status: false,
message: error.message
}))
} else {
resolve(
res.json({
status: true,
data: results,
message: 'Excel file successfully created in database'
}))
}
});
});
})
}
async function write() {
await database();
}
write();
}
After I got JSON from my Angular 6 front I put req.body into jsonData and try with forEach to put every object("value" in this case) into query and write that into Excel file.
You will have to wrap each query in a Promise and wait for all to complete before sending the response using Promise.all
Not that database() is going to throw when one of the queries fail and you won't have any access to the resolved promises.
const connection = require('./config');
module.exports.excel = function(req, res) {
const _query = 'INSERT INTO excel (id, first_name, last_name) values ?';
const jsonData = req.body;
function database() {
return Promise.all(
jsonData.map(
value =>
new Promise((resolve, reject) => {
const values = [value.id, value.first_name, value.last_name]
connection.query(_query, [values], (error, results) => {
if (error) {
reject(error.message);
return;
}
resolve(results);
});
})
)
);
}
async function write() {
try {
const results = await database();
res.json({
status: true,
data: results,
message: 'Excel file successfully created in database'
});
} catch (e) {
res.json({
status: false,
message: e.message
});
}
}
write();
};