How to use if else loop in Dialogflow for showing results - javascript

I have Javascript code for Dialogflow doing project on Google Actions. For this code if answer is in database means it will answer otherwise it is exiting out of app. So, I want to use else loop for this code plz help me
function handleCompanyDetails(agent){
const RegNo = agent.parameters.RegNo;
var ref8 = admin.database().ref().child("Table/");
var query8 = ref8.orderByChild("RegNo").equalTo(RegNo);
return query8.once("value")
.then(function(snapshot) {
snapshot.forEach(function(child) {
if( !snapshot.exists() ){
// There are no results, say so
agent.add("There are no results for that account.");
} else {
// ... Do something with the data
agent.add(`The student placed in ` + child.val().CompanyName);
}
});
});
}

While you can use a loop to show results, there are a few problems with how you've done to, and possibly even with what you're trying to return.
First - Dialogflow requires you to return a Promise from any function that makes an asynchronous call, such as a call to the Firebase database. You're currently using the callback method. You should switch to using once() that returns a Promise instead, so that might look something like this:
return query8.once("value")
.then( snapshot => {
// working with snapshot goes here
})
.catch( err => {
console.error(err);
agent.add("There was a problem.");
});
The second is how you work with snapshot itself. If you're expecting multiple results, you should be aware that you can only call agent.add() with a text message twice and one basic card. If you want multiple cards, you may want to use a list or carousel instead.
If you are expecting only one response indexed off the RegNo, which it looks like you may be, then you should just include that as part of the path and get the value of the snapshot. You wouldn't need a loop in this case.
Update based on updated code.
As you noted, you're not sending anything if there are no results, so the Action exits with an error.
The easiest way to do this is to use snapshot.exists() to check if there are any results in the snapshot. If there aren't any, then you can return an error. That might look something like
return query8.once("value")
.then(function(snapshot) {
if( !snapshot.exists() ){
// There are no results, say so
agent.add("There are no results for that account.");
} else {
// ... Do something with the data
}
});
// ...
If you do have results, you still have the issue that you may be sending back too many replies. You can only have one agent.add() with a message to be spoken (or two, at the most, but don't do that) and only one Card, unless you use a List or Carousel. So it would be better for you to build that message inside the loop.

Use .then() while doing operations on snapshot. Because .once() only triggers one time so if data is available meaning.then() will be executed and you can exit it using .catch(). check the code below.
function handleCompanyDetails(agent){
const RegNo = agent.parameters.RegNo;
var ref8 = admin.database().ref().child("Table/");
var query8 = ref8.orderByChild("RegNo").equalTo(RegNo);
return query8.once("value")
.then(function(snapshot) {
snapshot.forEach(function(child) {
agent.add(`The student placed in ` + child.val().CompanyName);
agent.add(new Card({
title: ` Name:${child.val().Studentname}
Reg No: ${child.val().RegNo}
Offer Date: ${child.val().OfferDate} `,
imageUrl: '',
text: `Thanks for using πŸ’\n ${child.val().FirstName} πŸ’`,
buttonText: '.com'
})
})
})
.catch( // throw some error)
}
you can read more here, https://firebase.google.com/docs/database/web/read-and-write

Related

Promise inside promise don't wait Axios finishing

I have a trouble. I receive many objects where I mapping them and I make a external consult using axios and save the return, let's the code:
let savedClients = Object.entries(documents).map(personDocument => {
let [person, document] = personDocument
documentFormated = document
documentNumbers = document.replace(/\D/g, '')
return ConsultDocuments.getResponse(documentNumbers).then(resultScore => { // Calling the axios
const info = { ...resultScore }
return Save.saveClient(info)
})
})
Promise.all(savedClients).then(results => {
console.log(results) // Come only one document, repeted with the total documents passed in map
})
The problem is when it realized the all map first and then make the consults with only the last result many time (the total of documents passed)
This code is legacy and use async/await don't work (serious, if i don't stay here)
I'am tried N ways to make this, and with the libary Q(), it's make the map in correcty order but it's doesn't wait the axios, and all results come with "pending"
Thanks!

How do I implement a find-or-create pattern in firestore

The firestore api has me a little mixed up in trying to have a repeatable pattern for find-or-create style functions. I'd like the canonical version to look like this:
// returns a promise resolving to a DocumentSnapshot (I think??)
function findOrCreateMyObject(myObject) {
return findMyObject(myObject.identifier).then(documentSnapshot => {
return (documentSnapshot)? documentSnapshot : createMyObject(myObject);
});
};
I'm not sure if DocumentSnapshot is the appropriate return from this, but I figure the caller may want to inspect or update the result, like this:
return findOrCreateMyObject({ identifier:'foo' }).then(documentSnapshot => {
console.log(documentSnapshot.data.someProperty);
return documentSnapshot.ref.update({ someProperty:'bar' });
});
Assuming I am right about that (please tell me if not), it means that both the find and create functions must return a DocumentSnapshot. This is easy enough for the find...
function findMyObject(identifier) {
let query = db.collection('my-object-collection').where('identifier','=='identifier);
return query.get().then(querySnapshot => {
return (querySnapshot.docs.length)? querySnapshot.docs[0] : null;
});
}
...but rather awkward for the create, and the the gist of my problem. I'd want to write create like this....
function createMyObject(myObject) {
// get db from admin
let collectionRef = db.collection('my-object-collection');
return db.collection('my-object-collection').doc().set(myObject);
}
But I cannot because DocumentReference set() resolves to a "non-null promise containing void". Void? I must read back the object I just wrote in order to get a reference to it? In other words, my idealized create needs to be rewritten to be slower and clunkier...
function createMyObject(myObject) {
// get db from admin
let collectionRef = db.collection('my-object-collection');
return db.collection('my-object-collection').doc().set(myObject).then(() => {
// must we query the thing just written?
return findMyObject(myObject.identifier); // frowny face
});
}
This makes my generic create longer (and unnecessarily so when doing just a create). Please tell me:
is DocumentSnapshot the right "currency" for these functions to traffic in?
Am I stuck with a set() and then another query when creating the new object?
Thanks!
EDIT As an example of where I would apply this, say I have customers, uniquely identified by email, and they have a status: 'gold', 'silver' or 'bronze'. My CRM system decides that someone identifying himself as doug#stevenson.com deserves 'silver' status. We don't know at this point wither Mr. Stevenson is a current customer, so we do a find-or-create...
findOrCreateCustomer({ email:'doug#stevenson.com' }).then(customer => {
customer.update({ status:'silver' });
});
I wouldn't just create, because the customer might exist. I wouldn't just update, because the customer might not exist, or might not meet some other criterion for the update.

How to wait for all dynamic number of forks to complete with redux-saga?

I'm trying to use redux saga to query a number of rest endpoints to get a human readable name associated with each discovered network, to fill a dropdown list with selectable networks.
I'm having trouble doing this, my forking is not working. I keep getting the error message:
TypeError: __webpack_require__.i(..) is not a function(...)
Every example using all() I've found online use call and know ahead of time every request being made. However, judging from the API I tried something like this:
const pendingQueries = [];
for(networkId in discoveredNetworks) {
pendingQueries.push(fork(getApplicationName, networkId);
}
const queryResults = yield all(pendingQueries);
This failed. I've tried a number of other permutations since. From testing I'm able to verify that I can do this:
const results = [];
for(networkId in discoveredNetworks) {
results.push(yield fork(getApplicationName, networkId));
}
and if There is a long enough delay the method will run and complete, though this approach obviously doesn't gaurentee that the forked methods will complete before I use result as I want. Still it seems to confirm the problem is in my use of all.
What is wrong with my all command?
Why don’t you wrap each request in a promise and call them like so:
var promises = []
for(networkId in discoveredNetworks) {
promises.push(new Promise((res, rej) => {
// code from getApplicationName goes here
// call res(result) on success and rej(error) on failure
}));
}
const results = yield call(Promise.all(promises))
I got this to work by giving up on the all() method, which I never got to work as advertised but wasn't really the right method for the job.
For forks I should have been using join() instead. so something along the lines of this:
const pendingQueries = [];
for(networkId in discoveredNetworks) {
pendingQueries.push(yield fork(getApplicationName, networkId);
}
const results = yield join(...pendingQueries);
results.forEach((result) => {
// my logic for handling the response and generating action
}

Why does one method of stacking promises in Lightswitch work when another doesn't?

I'm working with a Lightswitch 2015 application for tracking customer satisfaction interviews. I'm trying to create a function that will create a new interview, populate a few items, then save it to the database, and open it for editing in a new window. I'm struggling with understanding the behavior of promises in this context.
I have these three blocs of code:
1)
myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
var NewInterview = screen.Interviews.addNew();
NewInterview.c_Date = screen.InterviewDate;
NewInterview.Participant = screen.Interviewee;
NewInterview.Location = screen.InterviewFocusLocation;
screen.closePopup()
.then(() =>
{
myapp.applyChanges()
.then(() =>{ myapp.showInterview_AddEdit(NewInterview); });
}, (error) =>{ msls.showMessageBox(error.toString()); });
};
2)
myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
var NewInterview = screen.Interviews.addNew();
NewInterview.c_Date = screen.InterviewDate;
NewInterview.Participant = screen.Interviewee;
NewInterview.Location = screen.InterviewFocusLocation;
screen.closePopup()
.then(myapp.applyChanges()
.then(myapp.showInterview_AddEdit(NewInterview),
(error) =>{ msls.showMessageBox(error.toString()); })
);
};
3)
myapp.Interviews_Management.AddInterview_Tap_execute = function (screen)
{
var NewInterview = screen.Interviews.addNew();
NewInterview.c_Date = screen.InterviewDate;
NewInterview.Participant = screen.Interviewee;
NewInterview.Location = screen.InterviewFocusLocation;
screen.closePopup()
.then(myapp.applyChanges())
.then(myapp.showInterview_AddEdit(NewInterview),
(error) =>{ msls.showMessageBox(error.toString()); });
};
1 works as expected; that is, creates a new interview, populates the fields, and opens an edit window. However, I'm concerned that errors thrown from inside the lambda function(s) won't be properly passed to the external context.
2 and 3 both create a new interview and populate the fields, but then throws an error saying, "This action cannot be taken while screen is navigating.", which seems to suggest it is not waiting for each promise to fulfill before attempting to execute the next one. 3 also seems like perhaps it is wrapping promises in other promises, which may again lead to not properly passing any thrown errors outward (and, I hear, is a pretty common anti-pattern for people struggling with understanding promises?).
Can someone help me understand what exactly is going on here? I've been struggling generally with proper best practice in nesting promises or using a series of promises; any help with proper way of handling this would be much appreciated!
You always need to pass a callback function to then, not the result of calling it immediately.
You want
screen.closePopup()
.then(myapp.applyChanges) // or () => myapp.applyChanges()
.then(() => myapp.showInterview_AddEdit(NewInterview)),
.catch(error => { msls.showMessageBox(error.toString()); });
For why that catch is necessary (better than using the second then parameter), see When is .then(success, fail) considered an antipattern for promises?.

PouchDB gives 409 "Document update conflict" error with .put(), even with correct ._rev

I have a function that may either create or update documents in PouchDB, as follows. The function works perfectly when run the first time. However, every subsequent run yields a 409 error, even though the ._rev property appears to be correct.
function saveEventMatchesToDatabase(event, db) {
/* event: An event object from The Blue Alliance API. */
/* db: a reference ot the PouchDB database. */
/* Purpose: Given an event, extract the list of matches and teams, and save them to the database. */
TBA.event.matches(event.key, function(matches_list) {
var i = 0;
for (i = 0; i < matches_list.length; i++) {
var match = new Object();
var docrec = new Object();
match._id = 'matches/' + matches_list[i].key;
match.redTeam = matches_list[i].alliances.red.teams;
match.blueTeam = matches_list[i].alliances.blue.teams;
/* If the doc already exists, we need to add the _rev to update the existing doc. */
db.get(match._id).then(function(doc) {
match._rev = doc._rev;
docrec = doc;
}).catch(function(err) {
if ( err.status != 404 ) {
/* Ignore 404 errors: we expect them, if the doc is new. */
console.log(err);
}
});
db.put(match).then(function() {
// Success!
}).catch(function(err) {
console.log('\ndoc._rev: ' + docrec._rev);
console.log('match._rev: ' + match._rev);
console.log(err);
});
}
});
}
Sample console output from running this function the second time is below. The same error occurs for EVERY item in match_list, not just intermittently.
doc._rev: 1-7cfa2c6245dd939d8489159d8ca674d9
match._rev: 1-7cfa2c6245dd939d8489159d8ca674d9
r {status: 409, name: "conflict", message: "Document update conflict", error: true}
I'm not sure what I'm missing, that's causing this problem. Any suggestions for where to look next would be greatly appreciated.
The first problem seems to be that you're using a function within a loop, meaning that any variables used inside of the inner functions are randomly changing under your feet depending on when the function gets invoked. Instead of a for loop, you can use forEach().
However, the second problems is that you are not using promises correctly; you need to wait for the result of get() before you do your put(). So probably forEach() is not even what you want in the first place; you probably want to use Promise.all() and then compose your promises.
I wrote a piece on this awhile back; many people have told me that it's worth reading even though it's long: "We have a problem with promises." Read that, and you should hopefully understand promises by the end of it. :)

Categories

Resources