How to use agent.add()? - dialogflow-es

All the logs which are displayed by using console.log are shown. But agent doesn't display the response.
I try to use promise but do not know how to use it with this code.
function combineCollection(agent) {
console.log('At combineCollection');
return admin.firestore().collection('House').where('userId','==',lineId).get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log('find houseNo by userId');
houseNo = doc.id;
console.log('houseNo in combinefunction: '+houseNo);
console.log('before find invoice');
invoice();
});
})
.catch(function(error) {
console.log('Error getting documents: ', error);
});
}
function invoice(){
let price = 5;
console.log('houseNo: '+houseNo);
return admin.firestore().collection('Invoice').where('houseNo','==',houseNo).get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
console.log('find invoice by houseNo');
console.log(doc.id, " => ", doc.data());
price = doc.data().price;
console.log(price); // it's show
agent.add(price); // it's not show
});
})
.catch(function(error) {
console.log('Error getting documents: ', error);
});
}
let intentMap = new Map();
intentMap.set("aa",combineCollection);

In invoice() function, agent is not defined or got as parameter. So, it can not recognize the agent.add() function and can not respond. Add agent as parameter to your function and try again.
Also check these for async calls:
for Dialogflow
for Actions on Google

Related

Mongoose Error when using findOneAndUpdate

I have received an error at my server console during updating my Note collection, the update is successful but I receive this error in my server console, felt something wrong. Thanks in advance
app.put("/todos/:id", async(req,res) => {
try {
// console.log(req.body);
const { id } = req.params;
const { title, content } = req.body.edit;
const edit = await Note.findOneAndUpdate({_id:id}, {
title: title,
content: content
},
function (err, docs) {
if(!err){
console.log("Successfully edit item:" + docs);
const response = res.json(docs);
}else{
console.error(err);
}
})
// Example: Update name to Gourav
// User.findByIdAndUpdate(user_id, {
// name: 'Gourav'
// },
// function (err, docs) {
// if (err) {
// console.log(err)
// } else {
// console.log("Updated User : ", docs);
// }
// });
} catch (error) {
console.error(error);
}
});
Error msg:
MongooseError: Query was already executed: Note.findOneAndUpdate({
_id: new ObjectId("61580e469338c1fc3...
at model.Query._wrappedThunk [as _findOneAndUpdate] (C:\Users\xx\Desktop\MernToDoV3\server\node_modules\mongoose\lib\helpers\query\wrapThunk.js:21:19)
at C:\Users\xx\Desktop\MernToDoV3\server\node_modules\kareem\index.js:370:33
at processTicksAndRejections (internal/process/task_queues.js:77:11) { originalStack: 'Error\n' +
' at model.Query._wrappedThunk [as _findOneAndUpdate] (C:\Users\xx\Desktop\MernToDoV3\server\node_modules\mongoose\lib\helpers\query\wrapThunk.js:25:28)\n'
+
' at C:\Users\xx\Desktop\MernToDoV3\server\node_modules\kareem\index.js:370:33\n'
+
' at processTicksAndRejections (internal/process/task_queues.js:77:11)' }
I had similar issue with this query query.limit(resPerPage).skip(skip).
I chained clone() and it worked
query.limit(resPerPage).skip(skip).clone()
You can do something like this. You don't need to use the callbacks instead use async/await or then/catch.
When you apply try/catch to the async code, it doesn't go well. They are typically used to catch the errors when the code is synchronous by using different means. Promises provided a way to catch the error using catch operator.
app.post("/todos", async (req,res)=>{
try{
// const small = new Tank({ size: 'small' });
// small.save(function (err) {
// if (err) return handleError(err);
// // saved!
// });
console.log(req.body); //should use console to see
const { title, content} = req.body.newNote,
noteInput = new Note({title, content });
const result = await noteInput.save();
if (result) {
// check if the result exist else do something
// if you don't find anything
}
}catch(err){
// any errors in the save will be catch here automatically
console.error(err.message);
}
});
Note: When you make a function async, you need to use the await keyword to wait for the results for the async portion in the function.

Nodejs Promise "res.end is not a function" error

I'm refactoring my code to remove a "callback hell" using Promises, but encountered an error that I cannot pass. My code receives list of IDs and processes them making few database calls, that is why I had this "callback hell".
Everything worked fine until Promises. The res is equal 0 when I had to respond back to the client.
function processVMDelete(returnedVMIDs){
return new Promise((resolve, reject) => {
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlUpdateDELETE_STATE_ByVMID, [
'DELETE',
returnedVMIDs
], function(err, rows) {
if (err){
reject(err);
}
console.log('finish update');
// dont' need to return anything here
resolve(0);
});
mariasqlClient.end();
});
}
function getListExpVM(){
return new Promise((resolve, reject) => {
var vmList = [];
var mariasqlClient = dbConnection();
mariasqlClient.query( sqlSearch_ByUSERNAMEAndSTATE, [
requesterUsername,
'ACTIVE'
], function(err, rows) {
if (err){
reject(err);
}
vmList = filterExpiredVMs(rows);
var response = {
status : 200,
success : 'Successfull',
data : vmList,
requester: requesterUsername
};
resolve(response);
});
mariasqlClient.end();
});
}
router.post('/processVMs', function(req, res) {
var returnedVMIDs = JSON.parse(req.body.data);
processVMDelete(returnedVMIDs)
.then(res => {
console.log('done');
// check if there is more available for the user:
getListExpVM()
.then(response => {
console.log('sending back list of VMs');
//===>>> ERROR HERE: res.end is not a function
res.end(JSON.stringify(response));
})
.catch(err => {
console.log('error', err.message);
logger.error("Error getting expired VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
})
.catch(err => {
console.log('error', err.message);
logger.error("Error processing VMs: " + err.message);
//===>>> ERROR HERE: res.send is not a function
res.status(500).send({error: err.message})
});
});
You've redefined res with this:
processVMDelete(returnedVMIDs)
.then(res => {...})
This will hide the higher scoped res associated with the overall request (the one you need to use for res.end()). Change the name of this one to something else like result and then change the corresponding references that use this result.

Render the results of two separate async.each methods

I am new to nodejs and async. Having trouble understanding how can I wrap the two separate async.each methods to have one res.render...I am trying to display a list of valid account ids, and valid user ids on the front end.
The two separate async.each methods are:
async.each(account_ids, function(accountId, callback) {
console.log('Processing accountId ' + accountId);
callingExternalApi(accountId, callback, function(err, response){
if(err){
console.log("error account");
}
console.log("account response is: ", response);
});
}, function(err) {
if( err ) {
console.log('An account failed to process');
} else {
console.log('All accounts have been processed successfully');
}
});
and
async.each(email_ids, function(emailId, callback) {
console.log('Processing email id ' + emailId);
request({
url: emailIdlookupUrl,
method: 'POST',
json: {
email_address: emailId
}
}, function (err, response, body) {
if (err) {
logger.error(err);
req.flash('error', err.message);
return res.redirect('?');
}
if (response.statusCode !== 200) {
const msg = 'Unable to verify user';
req.flash('error', msg);
return res.redirect('?');
}
console.log("user id is: ", body.user.id);
callback();
});
}, function(err) {
if( err ) {
console.log('An email failed to process');
} else {
console.log('All user emails have been processed successfully');
}
});
Any help is highly appreciated. Please excuse me for any redundant callbacks or error logging. Still learning nodejs.
Thanks!!
The main issue is not that you are invoking both of these async.each calls. The problem is that they will run in parallel, and the fastest one to invoke req.* functions or callback function will return a response to the connection.
Both of these functions return promises if their callback parameters are omitted.
I recommend reading up on both the async library and JS async/await in general:
https://javascript.info/async-await
https://caolan.github.io/async/v3/docs.html#each
https://zellwk.com/blog/async-await-express/
Note that async also accepts native async functions, which many finder cleaner and easier to understand.
Here is what I think you want from the code above, including compiling the results into lists:
var request = require("request-promise");
async function checkAccounts(account_ids) {
const valid_accounts = [];
await async.each(account_ids, async function(accountId) {
console.log("Processing accountId " + accountId);
const extAPIresult = await callingExternalApi(accountId);
console.log("account response is: ", extAPIresult);
});
valid_accounts.push(extAPIresult);
console.log("All accounts have been processed successfully");
return valid_accounts;
}
async function checkEmails(email_ids) {
const valid_emails = [];
await async.each(email_ids, async function(emailId) {
console.log("Processing email id " + emailId);
const reqresult = await request({
url: emailIdlookupUrl,
method: "POST",
json: {
email_address: emailId
}
});
if (reqresult.statusCode !== 200) {
throw new Error("Unable to verify user");
}
valid_emails.push(reqresult.body.user.id);
console.log("user id is: ", reqresult.body.user.id);
});
console.log("All emails have been processed successfully");
return valid_emails;
}
async function doChecks() {
const accounts = checkAccounts(account_ids);
const emails = checkEmails(email_ids);
const responses = await Promises.all([accounts, emails]);
console.log("All checks have been processed successfully");
return responses;
}
function get(req, res) {
doChecks()
.then(responses => {
res.send("All checks have been processed successfully");
res.send(String(responses));
})
.catch(err => {
req.flash("error", err.message);
res.redirect("?");
});
}

Firebase Firestore transaction is returning a querySnapshot instead of a documentSnapshot

i'm replicating this code from the firebase documentation in google cloud functions:
var cityRef = db.collection('cities').doc('SF');
var transaction = db.runTransaction(t => {
return t.get(cityRef)
.then(doc => {
// Add one person to the city population
var newPopulation = doc.data().population + 1;
t.update(cityRef, { population: newPopulation });
});
}).then(result => {
console.log('Transaction success!');
}).catch(err => {
console.log('Transaction failure:', err);
});
But i get: property 'data' does not exist on type 'QuerySnapshot' when it should be a documentSnapshot.
I found the answer after i opened an issue on github and get some insight https://github.com/firebase/firebase-admin-node/issues/344
async function setCounts(storeRef: admin.firestore.DocumentReference) { // Type here
var transaction = admin.firestore().runTransaction(t => {
return t.get(storeRef)
.then((doc: admin.firestore.DocumentSnapshot) => { // Type here
x = doc.data(); // Now i can get data() from the doc
});
}).then(result => {
console.log('Transaction success!');
}).catch(error => {
console.log('Transaction failure:', error);
});
}
I finally made it work by explicitly declaring the types for DocumentReference and DocumentSnapshot, i don't know why, but while deploying the linter inferred doc as QuerySnapshot even though it was not.

Firebase admin sequential call, return values and promises

0) I have an HTTP trigger:
exports.checkout = functions.https.onRequest((req, res) => {
1) Update top up transactions when user buys topUp package:
admin.database().ref('topupTransaction').push(topUpObject)
2) Get the user object (with account balance)
admin.database().ref('/users/' + userID).once("value",snap=> {
3) Set the new user object (with new account balance)
admin.database().ref('/users/' + req.query.userUid).set(topUpObject);
I'm not sure how to run all these (1,2,3) sequentially and return a value to the client (0). Hitting shouldn't embed promise. There's Promise.all, but how to use it in this case.
Hitting "Avoid nesting promises." when I try to do it in this way:
exports.checkout = functions.https.onRequest((req, res) => {
var nonceFromTheClient = req.body.payment_method_nonce;
var topUpObject = {
amount : parseInt(req.query.topUpPackage),
date : admin.database.ServerValue.TIMESTAMP, // 1525451616097
user : req.query.userUid
};
admin.database().ref('topupTransaction').push(topUpObject)
.then((topUpResult) => {
return admin.database().ref('/users/' + userID).once("value");
}).then((oldUserData)=>{
return admin.database().ref('/users/' + req.query.userUid).set(topUpObject).then((newUserData)=>{
return res.send(newUserData.val());
})
;
}).catch((error) => {
// Update databse failed (top up transaction)
console.log('Error sending message:', error);
return res.status(500).send(error);
});
Update
using Promise.all, but working partially with errors:
// Create 2 functions
function asyncFunction1(topUpObject){
// Push top up object to database
admin.database().ref('topupTransaction').push(topUpObject)
.then((response) => {
// Update databse successful (top up transaction)
console.log('Top Up transaction created successfully!', topUpObject);
// return res.redirect(303, response.ref);
return topUpObject;
}).catch((error) => {
// Update databse failed (top up transaction)
console.log('Error sending message:', error);
return error;
});
}
function asyncFunction2(userID,topUpObject){
// Get the user account balance
console.log('Current User ID: ', userID);
var ref = admin.database().ref('users').child(userID);
admin.database().ref('/users/' + userID).once("value",snap=> {
// do some stuff once
console.log('Current User Data',snap.val());
console.log('Current User balance',snap.val().accountBalance);
var userContents = snap.val();
var currentBalance = userContents.accountBalance;
var updatedBalance = currentBalance + topUpObject.amount;
console.log('Updated Balance',updatedBalance);
userContents.accountBalance = updatedBalance;
/*Current User Data {
accountBalance: 0,
accountCurrency: 'MYR',
createdOn: '2018-05-02T20:42:49Z',
phoneNumber: '+123445555555'
}
*/
admin.database().ref('/users/' + userID).set(userContents).then(snapshot => {
console.log('Updated top up value! for user', topUpObject);
return res.send(topUpObject.amount);
}).catch((error) => {
// Update databse failed (top up transaction)
console.log('Error sending message:', error);
return error;
});
});
}
// app.post("/checkout", function (req, res) {
exports.checkout = functions.https.onRequest((req, res) => {
var nonceFromTheClient = req.body.payment_method_nonce;
// Use payment method nonce here
// Create Transaction
gateway.transaction.sale({
amount: req.query.topUpPackage,
paymentMethodNonce: nonceFromTheClient,
options: {
submitForSettlement: true
}
},(err, result) => { //TODO: What should we pass back here???
if (err) {
// If top up error (from braintree)
console.log(err.stack);
}else{
// If top up is successful
console.log('Result:',result);
console.log('Top Up Package is: ', req.query.topUpPackage);
var topUpObject = {
amount : parseInt(req.query.topUpPackage),
date : admin.database.ServerValue.TIMESTAMP, // 1525451616097
user : req.query.userUid
};
return Promise.all([asyncFunction1(topUpObject), asyncFunction2(req.query.userUid,topUpObject)]); //TODO: how to pass back res() to client???
}
// Return the error as response
return res.send(err);
});
});
exports.client_token = functions.https.onRequest((req, res) => {
// a token needs to be generated on each request
// so we nest this inside the request handler
// Need to write a function to return a client token,
// and return it back by using the res.send command
console.log('Log customerId',req.query.text);
gateway.clientToken.generate({
// customerId: req.query.text
}, (err, response) => {
// error handling for connection issues
if (err) {
console.log(err.stack);
}else{
clientToken = response.clientToken;
console.log('Log Client token:',clientToken);
return res.send(clientToken);
}
return res.send(err);
});
// return null;
});
There are, in my humble opinion, a couple of things to be fine-tuned in your code, as follows. I've commented in the code.
However, note that since we don't know from where topUpObject comes from (and what it is) it is a bit difficult to be more precise. If you share more details (the full Cloud Function code and the database structure) I may be more precise.
admin.database().ref('topupTransaction').push(topUpObject)
.then(topUpResult => {
return admin.database().ref('/users/' + userID).once("value");
})
.then(oldUserData => {
return admin.database().ref('/users/' + req.query.userUid).set(topUpObject);
//Set returns a non-null firebase.Promise containing void
})
.then(() => { //so I don't think you can get the newUserData here
//return res.send(newUserData.val()); <- and therefore you cannot do that here
//But if I understand well you want to send back to the user the topUpObject, so do as follows:
return res.status(200).send(topUpObject); //<- note the addition of status(200) here
})
.catch((error) => {
// Update databse failed (top up transaction)
console.log('Error sending message:', error);
return res.status(500).send(error);
});

Resources